Python';s非本地关键字-这是一个好做法吗?
考虑一个简单的情况,例如在BST中查找第k个最小元素 在我下面的解决方案中:Python';s非本地关键字-这是一个好做法吗?,python,python-3.x,encapsulation,Python,Python 3.x,Encapsulation,考虑一个简单的情况,例如在BST中查找第k个最小元素 在我下面的解决方案中: class Solution: def kthSmallest(self, root: TreeNode, k: int) -> int: i = 0 ans = -1 def traverse_inorder(root): nonlocal i nonlocal ans if not
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
i = 0
ans = -1
def traverse_inorder(root):
nonlocal i
nonlocal ans
if not root:
return
traverse_inorder(root.left)
i += 1
if i == k:
ans = root.val
return
traverse_inorder(root.right)
traverse_inorder(root)
return ans
我对i
和ans
使用nonlocal
是否是良好做法?我这样做是为了跟踪到达最左侧节点(最小值)后经过的元素数
另一个解决方案是将i
和ans
作为类的成员变量:
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
self.i = 0
self.ans = -1
def traverse_inorder(root):
# etc etc
这两种方法是等效的吗?一种做法比另一种好吗?为什么?我认为,在您描述的情况下,您客观地描述的
非本地
方法从所示的两种方法中更有意义。您希望在函数外有一个计数器,并且无论在递归中的什么位置,都可以在找到结果时跟踪它
nonlocal
将该信息完全封装在专用于外部函数特定运行的命名空间中。这里真的没有坏处
使用实例属性可以使使用该实例的任何人都可以使用该信息。这在概念上是不必要的,速度稍微慢一些,而且不是线程安全的。虽然线程安全在Python中通常不受关注,但它确实会使代码的健壮性大大降低。在这和封装之间,我绝对不会使用这种方法
我在此建议第三种可能性:使用返回值。在这种情况下,您实际上不需要任何外部名称空间。我不一定推荐使用非本地
,但值得一提。下面是一个示例实现,正如您所看到的,它比您的解决方案要详细得多:
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
def traverse_inorder(root, target):
if not root:
return 0, None
left_count, item = traverse_inorder(root.left, target)
if left_count == target - 1:
return left_count + 1, root.val
elif left_count < target:
right_count, item = traverse_inorder(root.right, target - left_count - 1)
return left_count + right_count + 1, item
else: # left_count == target
return left_count, item
count, ans = traverse_inorder(root, k)
if count < k:
raise ValueError('Insufficient elements')
return ans
类解决方案:
def kthSmallest(self,root:TreeNode,k:int)->int:
def遍历顺序(根、目标):
如果不是根目录:
返回0,无
左\计数,项=遍历\顺序(root.left,target)
如果left_count==目标-1:
返回左_计数+1,root.val
elif左_计数<目标:
右\u计数,项=遍历\u顺序(root.right,target-left\u计数-1)
返回左计数+右计数+1,项目
否则:#左#计数==目标
返回左\u计数,项目
计数,ans=按顺序遍历(根,k)
如果计数
有很多方法可以通过返回值实现这一点。这里,我计算每个子树中元素的数量,直到目标值。只有在找到元素的确切数量时,才会返回非none项。我认为,在您描述的情况下,您客观描述的
非本地
方法从所示的两个方面更具意义。您希望在函数外有一个计数器,并且无论在递归中的什么位置,都可以在找到结果时跟踪它
nonlocal
将该信息完全封装在专用于外部函数特定运行的命名空间中。这里真的没有坏处
使用实例属性可以使使用该实例的任何人都可以使用该信息。这在概念上是不必要的,速度稍微慢一些,而且不是线程安全的。虽然线程安全在Python中通常不受关注,但它确实会使代码的健壮性大大降低。在这和封装之间,我绝对不会使用这种方法
我在此建议第三种可能性:使用返回值。在这种情况下,您实际上不需要任何外部名称空间。我不一定推荐使用非本地
,但值得一提。下面是一个示例实现,正如您所看到的,它比您的解决方案要详细得多:
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
def traverse_inorder(root, target):
if not root:
return 0, None
left_count, item = traverse_inorder(root.left, target)
if left_count == target - 1:
return left_count + 1, root.val
elif left_count < target:
right_count, item = traverse_inorder(root.right, target - left_count - 1)
return left_count + right_count + 1, item
else: # left_count == target
return left_count, item
count, ans = traverse_inorder(root, k)
if count < k:
raise ValueError('Insufficient elements')
return ans
类解决方案:
def kthSmallest(self,root:TreeNode,k:int)->int:
def遍历顺序(根、目标):
如果不是根目录:
返回0,无
左\计数,项=遍历\顺序(root.left,target)
如果left_count==目标-1:
返回左_计数+1,root.val
elif左_计数<目标:
右\u计数,项=遍历\u顺序(root.right,target-left\u计数-1)
返回左计数+右计数+1,项目
否则:#左#计数==目标
返回左\u计数,项目
计数,ans=按顺序遍历(根,k)
如果计数
有很多方法可以通过返回值实现这一点。这里,我计算每个子树中元素的数量,直到目标值。只有在找到元素的确切数目时,才会返回非none项。是否有效?它似乎封装得很好,所以我认为它很好。使其成为类的成员可以允许其他人修改它。是的,它可以工作。嗯,这是真的,我认为这两个变量(特别是我)与类的其他方法不相关,所以在这种情况下,非局部方法实际上更好。非常感谢。我已经添加了一个答案供您选择(希望是向上投票),这样您就可以从未回答的队列中删除您的问题。希望它添加的不仅仅是我们注释的扩展版本。顺便说一句,我已经在第二个解决方案中将变量初始化移动到
kthSmallest
方法中。如果不这样做的话,这个设计将是非常值得怀疑的。它有效吗?它似乎封装得很好,所以我认为它很好。使其成为类的成员可以允许其他人修改它。是的,它可以工作。嗯,这是真的,我认为这两个变量(特别是我)与类的其他方法不相关,所以在这种情况下,非局部方法实际上更好。非常感谢。我已经添加了一个答案供您选择(希望是向上投票),这样您就可以从未回答的队列中删除您的问题。希望它能带来更多的好处