mirror of
https://github.com/apachecn/ailearning.git
synced 2026-02-09 13:25:39 +08:00
400 lines
4.3 KiB
Markdown
400 lines
4.3 KiB
Markdown
# 修饰符
|
||
|
||
## 函数是一种对象
|
||
|
||
在 `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')
|
||
|
||
``` |