1.装饰器decorator
实质是一个迭代器,把定义的函数作为一个属性来调用。具体来看:
def hello(fn):
print(1)
def wrapper():
print(2)
print("hello, %s" % fn.__name__)
fn() # 在这里会调用foo()
print("goodby, %s" % fn.__name__)
return wrapper
@hello
def fool():
print("I'm a fool")
fool() # output 1/2/hello,fool/I'm a fool/goodby,fool
# @decorator
# def func():
# pass
# func = decorator(func)
这里,调用fool函数时,装饰器把fool函数,作为hello函数中的变量fn调用。实际是:
fool()=hello(fool()) # fn=fool()
装饰器的名字就是那个调用fool函数的函数名。
把函数当作参量调用是装饰器的一大特点。
修饰去加参数
# 装饰器加参数
def wap(name):
def decorator1(func):
def dec(*args):
print(name)
print ('pre action')
result = func(*args)
print('post action')
return result
return dec
return decorator1
@wap('f1')
def test_f1(name):
print(name)
return None
@wap('f2')
def test_f2(name):
print(name)
return None
test_f1('name1') #out: f1/pre action/name1/post action
test_f1('name2') #out: f2/pre action/name2/post action
test_f1('name')=wap('f1')(test_f1('name')) # f1和test_f1都是参数
也可以用多个修饰器,实现多层嵌套调用。
def decorator1(func):
def dec(*args):
print('d1 pre')
result = func(*args) # func的参数传递给了dec
print('d1 post')
return result
return dec
def decorator2(func):
def dec(*args):
print('d2 pre')
result = func(*args)
print('d2 post')
return result
return dec
@decorator1
@decorator2
def test(name):
print(name)
test('a')
d1 pre
d2 pre
a
d2 post
d1 post
test('a')=decorator1(decorator2(test('a')))
2.property
property是python中的一个内置函数。定义式是:property(fget=None,fset=None,fdel=None,doc=None)
property的第一个变量fget是获取变量的函数,fset是设置变量,fdel删除变量。具体实现:
class C(object):
def __init__(self):
self._x = None
print('init')
def getx(self):
print('get')
return self._x # self._x相当于被隐藏了,外面只能看见x,对x赋值,就是对_x赋值
def setx(self, value):
self._x = value
print('set')
def delx(self):
del self._x
print('del')
x = property(fget = getx, fset = setx, fdel = delx, "I'm the 'x' property.")
# 定义property为x后,调用x时会自然调用getx,setx,delx
if __name__ == "__main__":
c=C() # 这里调用了getx
c.x=1 # x是定义的property函数,可以直接在类地下调用,且调用不需要像调用其他方法一样加(). #调用setx
print(c.x) # 调用getx
c.delx() # 调用delx
print(c.x) # 调用getx
init
set
get
1
del
get
Traceback (most recent call last):
File "C:/Users/C/Desktop/pr/test6.py", line 23, in <module>
print(c.x)
File "C:/Users/C/Desktop/pr/test6.py", line 8, in getx
return self._x
AttributeError: 'C' object has no attribute '_x'
# 这个方式定义的作用和上面的相同
x是定义的property函数,可以直接在类地下调用,且调用不需要像调用其他方法一样加().这里:
fget = getx, fset = setx, fdel = delx
class Celsius(object): # 1
def __init__(self, tem = 0):
print('init value')
self.c = tem
def to_fahrenheit(self):
return (self.c * 1.8) + 32
def get_temperature(self):
print
("Getting value")
return self.pro_tem
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.pro_tem = valueproperty有一个优点,就在于可以
# temperature是一个property属性,可以直接在类下调用,
temperature = property(get_temperature,set_temperature)
执行:
if __name__ == "__main__":
c=Celsius()
c.temperature=-300
init value
Traceback (most recent call last):
File "C:/Users/C/Desktop/pr/test6.py", line 23, in <module>
c.temperature=-300
File "C:/Users/C/Desktop/pr/test6.py", line 15, in set_temperature
raise ValueError("Temperature below -273 is not possible")
ValueError: Temperature below -273 is not possible
如果用常规的方法,则由于python中的语法规则,会依然执行,达不到效果。如:
class Celsius(object): # 2
def __init__(self, tem = 0):
print('init value')
if tem < -300:
raise ValueError("Temperature below -273 is not possible")
else:
self.c = tem
def to_fahrenheit(self):
return (self.c * 1.8) + 32
if __name__ == "__main__":
c=Celsius(tem=0) # 写成c=Celsius(tem=-300)同样
c.c=-300 # 强制赋值,不报错
>>>
================== RESTART: C:/Users/C/Desktop/pr/test6.py ==================
init value
这也是property的优点。因为可以不直接对x操作??
if __name__ == "__main__":
c=Celsius(-300)
# c.temperature=-300
print(c.temperature)
这种方式直接给tem赋值,也绕开了temporture函数,因此property就失效了。输出也是没法检测到ValueError的。
3.更进一步的用法
从形式上看,显然可以把property作为一个装饰器。也就是@property,这也是更常见的用法。
# 这个方式定义的作用和上面的1相同
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
print('getter')
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
print("setter")
self._x = value
@x.deleter
def x(self):
print('del')
del self._x
if __name__ == "__main__":
c=C()
c.x=2
print(c.x)
# 不知道怎么调用deleter
定义的property函数中有三个变量getter,setter,deleter和之前1中的fget,fset,fdel对应。输出:
setter
getter
2
一般是不会调用deleter的,甚至只有一个getter,也就是
@property
def func():
“内容”
class Parrot(object):
def __init__(self):
self._voltage = 100000
@property
def voltage(self):
"""Get the current voltage."""
return self._voltage
@voltage.setter
def voltage(self,value):
self._voltage=value
if __name__ == "__main__":
# instance
p = Parrot() #实例化类Parrot
# similarly invoke "getter" via @property 调用p.voltage() 相当于调用@property的getter方法
print (p.voltage)