about 3 years ago

Know How Closures Interact with Variable Scope

closure看似簡單,但是不小心的話有陷阱的(scoping bugs)。

def sort_priority2(numbers, group):
    found = False
    def helper(x):
        if x in group:
            found = True  # Seems simple

            return (0, x)
        return (1, x)
    numbers.sort(key=helper)
    return found

Python scope: L -> E -> G -> B
helper() 裡面的 found 屬於 helper() 的 local scope,跟外層的 found 不相干。
Python 3 提供 nonlocal 來處理這類情況,畢竟都有 global 了,對於 enclosed scope 也該有類似的東西。

def sort_priority3(numbers, group):
    found = False
    def helper(x):
        nonlocal found
        if x in group:
            found = True
            return (0, x)
        return (1, x)
    numbers.sort(key=helper)
    return found

Python 2 也是有 workaround,不過有點醜

def sort_priority(numbers, group):
    found = [False]
    def helper(x):
        if x in group:
            found[0] = True
            return (0, x)
        return (1, x)
    numbers.sort(key=helper)
    return found[0]

上面的方式都容易造成可讀性變差,有個選項是另外弄個 helper class

class Sorter(object):
    def __init__(self, group):
        self.group = group
        self.found = False

    def __call__(self, x):
        if x in self.group:
            self.found = True
            return (0, x)
        return (1, x)

sorter = Sorter(group)
numbers.sort(key=sorter)
← Effective Python 心得筆記: Item 14 Effective Python 心得筆記: Item 16 →
 
comments powered by Disqus