Files
ailearning/docs/da/075.md
2020-10-19 21:08:55 +08:00

400 lines
4.3 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 修饰符
## 函数是一种对象
`Python` 中,函数是也是一种对象。
In [1]:
```py
def foo(x):
print x
print(type(foo))
```
```py
<type 'function'>
```
查看函数拥有的方法:
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')
```