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

295 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.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 修饰符的使用
## @classmethod 修饰符
`Python` 标准库中,有很多自带的修饰符,例如 `classmethod` 将一个对象方法转换了类方法:
In [1]:
```py
class Foo(object):
@classmethod
def bar(cls, x):
print 'the input is', x
def __init__(self):
pass
```
类方法可以通过 `类名.方法` 来调用:
In [2]:
```py
Foo.bar(12)
```
```py
the input is 12
```
## @property 修饰符
有时候,我们希望像 **Java** 一样支持 `getters``setters` 的方法,这时候就可以使用 `property` 修饰符:
In [3]:
```py
class Foo(object):
def __init__(self, data):
self.data = data
@property
def x(self):
return self.data
```
此时可以使用 `.x` 这个属性查看数据(不需要加上括号):
In [4]:
```py
foo = Foo(23)
foo.x
```
Out[4]:
```py
23
```
这样做的好处在于,这个属性是只读的:
In [5]:
```py
foo.x = 1
```
```py
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-5-e5e7e6c675ef> in <module>()
----> 1 foo.x = 1
AttributeError: can't set attribute
```
如果想让它变成可读写,可以加上一个修饰符 `@x.setter`
In [6]:
```py
class Foo(object):
def __init__(self, data):
self.data = data
@property
def x(self):
return self.data
@x.setter
def x(self, value):
self.data = value
```
In [7]:
```py
foo = Foo(23)
print foo.x
```
```py
23
```
可以通过属性改变它的值:
In [8]:
```py
foo.x = 1
print foo.x
```
```py
1
```
## Numpy 的 @vectorize 修饰符
`numpy``vectorize` 函数讲一个函数转换为 `ufunc`,事实上它也是一个修饰符:
In [9]:
```py
from numpy import vectorize, arange
@vectorize
def f(x):
if x <= 0:
return x
else:
return 0
f(arange(-10.0,10.0))
```
Out[9]:
```py
array([-10., -9., -8., -7., -6., -5., -4., -3., -2., -1., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0.])
```
## 注册一个函数
来看这样的一个例子,定义一个类:
In [10]:
```py
class Registry(object):
def __init__(self):
self._data = {}
def register(self, f, name=None):
if name == None:
name = f.__name__
self._data[name] = f
setattr(self, name, f)
```
`register` 方法接受一个函数,将这个函数名作为属性注册到对象中。
产生该类的一个对象:
In [11]:
```py
registry = Registry()
```
使用该对象的 `register` 方法作为修饰符:
In [12]:
```py
@registry.register
def greeting():
print "hello world"
```
这样这个函数就被注册到 `registry` 这个对象中去了:
In [13]:
```py
registry._data
```
Out[13]:
```py
{'greeting': <function __main__.greeting>}
```
In [14]:
```py
registry.greeting
```
Out[14]:
```py
<function __main__.greeting>
```
[flask](flask.pocoo.org) ,一个常用的网络应用,处理 url 的机制跟这个类似。
## 使用 @wraps
一个通常的问题在于:
In [15]:
```py
def logging_call(f):
def wrapper(*a, **kw):
print 'calling {}'.format(f.__name__)
return f(*a, **kw)
return wrapper
@logging_call
def square(x):
'''
square function.
'''
return x ** 2
print square.__doc__, square.__name__
```
```py
None wrapper
```
我们使用修饰符之后,`square``metadata` 完全丢失了,返回的函数名与函数的 `docstring` 都不对。
一个解决的方法是从 `functools` 模块导入 `wraps` 修饰符来修饰我们的修饰符:
In [16]:
```py
import functools
def logging_call(f):
@functools.wraps(f)
def wrapper(*a, **kw):
print 'calling {}'.format(f.__name__)
return f(*a, **kw)
return wrapper
@logging_call
def square(x):
'''
square function.
'''
return x ** 2
print square.__doc__, square.__name__
```
```py
square function.
square
```
现在这个问题解决了,所以在自定义修饰符方法的时候为了避免出现不必要的麻烦,尽量使用 `wraps` 来修饰修饰符!
## Class 修饰符
与函数修饰符类似,类修饰符是这样一类函数,接受一个类作为参数,通常返回一个新的类。