很多时候我们写python的方式并不专业,不pythonic。今天就来讲讲pythonic的写法

先问自己几个问题,什么是闭包,什么是钩子函数,什么是__call__()方法?

一、什么是闭包,引用维基百科当中的一段话在计算机科学中,闭包(英语:Closure),又稱词法闭包(Lexical Closure)或函數閉包(function closures),

是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

引用wiki百科中的一段话 ,但是很多人看这个仍然不明白。其实最重要的还是先明白作用域和函数值。

二、词法作用域和函数当作值传递

1)作用域:

就是,按照代码书写时的样子,内部函数可以访问函数外面的变量。

引擎通过数据结构和算法表示一个函数,使得在代码解释执行时按照词法作用域的规则,

可以访问外围的变量,这些变量就登记在相应的数据结构中。

2)函数是python中的一等公民,可以像传递值那样传递函数。

就是可以把函数当作一个值来赋值,当作参数传给别的函数,也可以把函数当作一个值 return。

一个函数被当作值返回时,也就相当于返回了一个通道,

这个通道可以访问这个函数词法作用域中的变量,

即函数所需要的数据结构保存了下来,

数据结构中的值在外层函数执行时创建,

外层函数执行完毕时理因销毁,但由于内部函数作为值返回出去,这些值得以保存下来。

而且无法直接访问,必须通过返回的函数。这也就是私有性。

三、举个例子

current = {'green': 12, 'blue': 3}
increment = [('red',5),('blue',12),('orange',9)]
def increment_with_report(current,increment):
added_count = 0
def missing():
nonlocal added_count
added_count+=1
return 0
result = defaultdict(missing, current)
for key,amount in increment:
result[key] += amount
return result, added_count
result ,count = increment_with_report(current,increment)
print(count)

通过nonlocal关键字,我们改变了变量的作用域,使得外层added_count的值被改变。

missing函数作为值,被传递进去。最后return返回added_count值。

missing函数就被称作为一个钩子函数。

四、增强版

由于代码的可读性差,为了增强代码的可读性的,我们将missing方法改写成一个类中的__call__()方法。

通过__call__()特殊方法,可以使类的实例能像python函数一样被调用

class BetterCountMissing(object):
def __init__(self):
self.added = 0
def __call__(self):
self.added += 1
return 0
counter = BetterCountMissing()
result = defaultdict(counter,current)
for key, amount in increment:
result[key] += amount
print(counter.added)

五、总结

函数是python中的一等公民,可以像传递值那样传递函数。

函数和方法可以像类一样引用。通过__call__()特殊方法,可以使类的实例能像python函数一样被调用。

使用函数来保存状态应该定义新的类,并实现__call__()方法。尽量不使用带状态的闭包,因为这是python不是js。