# 修饰符 ## 函数是一种对象 在 `Python` 中,函数是也是一种对象。 In [1]: ```py def foo(x): print x print(type(foo)) ``` ```py ``` 查看函数拥有的方法: In [2]: ```py dir(foo) ``` Out[2]: ```py ['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name'] ``` 在这些方法中,`__call__` 是最重要的一种方法: In [3]: ```py foo.__call__(42) ``` ```py 42 ``` 相当于: In [4]: ```py foo(42) ``` ```py 42 ``` 因为函数是对象,所以函数可以作为参数传入另一个函数: In [5]: ```py def bar(f, x): x += 1 f(x) ``` In [6]: ```py bar(foo, 4) ``` ```py 5 ``` ## 修饰符 修饰符是这样的一种函数,它接受一个函数作为输入,通常输出也是一个函数: In [7]: ```py def dec(f): print 'I am decorating function', id(f) return f ``` 将 `len` 函数作为参数传入这个修饰符函数: In [8]: ```py declen = dec(len) ``` ```py I am decorating function 33716168 ``` 使用这个新生成的函数: In [9]: ```py declen([10,20,30]) ``` Out[9]: ```py 3 ``` 上面的例子中,我们仅仅返回了函数的本身,也可以利用这个函数生成一个新的函数,看一个新的例子: In [10]: ```py def loud(f): def new_func(*args, **kw): print 'calling with', args, kw rtn = f(*args, **kw) print 'return value is', rtn return rtn return new_func ``` In [11]: ```py loudlen = loud(len) ``` In [12]: ```py loudlen([10, 20, 30]) ``` ```py calling with ([10, 20, 30],) {} return value is 3 ``` Out[12]: ```py 3 ``` ## 用 @ 来使用修饰符 `Python` 使用 `@` 符号来将某个函数替换为修饰符之后的函数: 例如这个函数: In [13]: ```py def foo(x): print x foo = dec(foo) ``` ```py I am decorating function 64021672 ``` 可以替换为: In [14]: ```py @dec def foo(x): print x ``` ```py I am decorating function 64021112 ``` 事实上,如果修饰符返回的是一个函数,那么可以链式的使用修饰符: ```py @dec1 @dec2 def foo(x): print x ``` 使用修饰符 `loud` 来定义这个函数: In [15]: ```py @loud def foo(x): print x ``` In [16]: ```py foo(42) ``` ```py calling with (42,) {} 42 return value is None ``` ## 例子 定义两个修饰器函数,一个将原来的函数值加一,另一个乘二: In [17]: ```py def plus_one(f): def new_func(x): return f(x) + 1 return new_func def times_two(f): def new_func(x): return f(x) * 2 return new_func ``` 定义函数,先乘二再加一: In [18]: ```py @plus_one @times_two def foo(x): return int(x) ``` In [19]: ```py foo(13) ``` Out[19]: ```py 27 ``` ## 修饰器工厂 `decorators factories` 是返回修饰器的函数,例如: In [20]: ```py def super_dec(x, y, z): def dec(f): def new_func(*args, **kw): print x + y + z return f(*args, **kw) return new_func return dec ``` 它的作用在于产生一个可以接受参数的修饰器,例如我们想将 `loud` 输出的内容写入一个文件去,可以这样做: In [21]: ```py def super_loud(filename): fp = open(filename, 'w') def loud(f): def new_func(*args, **kw): fp.write('calling with' + str(args) + str(kw)) # 确保内容被写入 fp.flush() fp.close() rtn = f(*args, **kw) return rtn return new_func return loud ``` 可以这样使用这个修饰器工厂: In [22]: ```py @super_loud('test.txt') def foo(x): print x ``` 调用 `foo` 就会在文件中写入内容: In [23]: ```py foo(12) ``` ```py 12 ``` 查看文件内容: In [24]: ```py with open('test.txt') as fp: print fp.read() ``` ```py calling with(12,){} ``` In [25]: ```py import os os.remove('test.txt') ```