之前分享通过一般的方法创建property,本文主要分享一下通过装饰器来创建property。

1、简单介绍一下装饰器

简单来说,装饰器就是在不改变原来的函数代码的情况下,给原来的函数添加功能。下面通过代码介绍一下装饰器:

import time
def log_calls(func):
def wrapper(*args,**kwargs):
now = time.time()
print("Calling {0} with {1} and {2}".format(func.__name__,args,kwargs))
return_value = func(*args, **kwargs)
print("Executed {0} in {1}ms".format(func.__name__,time.time()-now))
return return_value
return wrapper
def test1(a,b,c):
print("test1 called")
def test2(a,b):
print("test2 called")
def test3(a,b):
print("test3 called")
time.sleep(1)
test1 = log_calls(test1)
test2 = log_calls(test2)
test3 = log_calls(test3)

>>> test1(1,2,3)
Calling test1 with (1, 2, 3) and {}
test1 called
Executed test1 in 0.00017595291137695312ms
>>> test2(4,b=5)
Calling test2 with (4,) and {'b': 5}
test2 called
Executed test2 in 9.918212890625e-05ms
>>> test3(6,7)
Calling test3 with (6, 7) and {}
test3 called
Executed test3 in 1.0013248920440674ms

上面的代码可以通过装饰器这样改写,

import time
def log_calls(func):
def wrapper(*args,**kwargs):
now = time.time()
print("Calling {0} with {1} and {2}".format(func.__name__,args,kwargs))
return_value = func(*args, **kwargs)
print("Executed {0} in {1}ms".format(func.__name__,time.time()-now))
return return_value
return wrapper
@log_calls
def test1(a,b,c):
print("test1 called")
@log_calls
def test2(a,b):
print("test2 called")
@log_calls
def test3(a,b):
print("test3 called")
time.sleep(1)

>>> test1(1,2,3)
Calling test1 with (1, 2, 3) and {}
test1 called
Executed test1 in 0.00017595291137695312ms
>>> test2(4,b=5)
Calling test2 with (4,) and {'b': 5}
test2 called
Executed test2 in 9.918212890625e-05ms
>>> test3(6,7)
Calling test3 with (6, 7) and {}
test3 called
Executed test3 in 1.0013248920440674ms

@log_calls这样的写法就是使用装饰器

2、通过装饰器创建property

class Dog:
@property
def age(self):
print("You are getting age")
return self._age
@age.setter
def age(self, value):
print("You are setting age {}".format(value))
self._age = value
@age.deleter
def age(self):
print("You killed age!")
del self._age

>>> d = Dog()
>>> d.age=11
You are setting age 11
>>> d.age
You are getting age
>>> del d.age
You killed age!

上面代码中property成为一个装饰器,这相当于应用了 age = property(age)。接着用刚装饰过的age方法的setter属性又装了一个新方法,而这个新方法的名字和刚装饰过的age是一样的,请一定记住,property函数返回的是一个对象,这个对象被自动设置有一个setter属性,而这个setter属性可以被设置成一个装饿器去装饰其它的函数。还可以用@age.deleter指定一个删除函数,但不能通过property装饰器来指定描述文本字符串。