目录
(3)类中的某些属性被封装之后,想在类外改变属性的值,做法如下:
1.装饰器的本质
闭包函数 @闭包函数名
https://blog.youkuaiyun.com/g_optimistic/article/details/86486937
2.装饰器的引出
练习:计算程序花费的时间
(1)正常函数:
import time
def func():
start = time.time()
for i in range(1000000):
pass
end = time.time()
print(end - start) # 0.031199932098388672
func()
(2)闭包函数:
(3)装饰器
@闭包函数名
import time
def otter(fun):
def inner():
start = time.time()
ret = fun()
end = time.time()
print(end - start)
return ret
return inner
@otter # 等价于:inner=otter(func)
def func():
for i in range(1000000):
pass
return 'ok'
ret = func()
print(ret)
# 0.015599966049194336
# ok
3.传一个参数
import time
def otter(fun):
print('xxx')
def inner(s):
start = time.time()
ret = fun(s)
end = time.time()
print(end - start)
return ret
return inner
@otter # 等价于:inner=otter(func)
def func(s):
for i in range(1000000):
pass
return s
ret = func('hello')
print(ret)
# xxx
# 0.015599966049194336
# hello
4.传多个参数 *args **kwargs
如果用一个变量来接收,输出来是元组
如果用两个变量来接收,输出来的也是元祖
用元组接收 *args 返回的值
用字典接收 **kwargs 返回的值
import time
def otter(fun):
print('xxx')
def inner(*args, **kwargs):
start = time.time()
ret = fun(*args, **kwargs)
end = time.time()
return ret
return inner
@otter
def func(*args, **kwargs):
for i in range(1000000):
pass
return args, kwargs
ret = func('hello', name='zs', age=10)
print(ret)
# xxx
# (('hello',), {'name': 'zs', 'age': 10})
ret, ret1 = func('hello', name='zs', age=10)
print(ret, ret1) # ('hello',) {'name': 'zs', 'age': 10}
# 如果用一个变量来接收,输出来是元组
# 如果用多个变量来接受,用元组来接收*args的值,用字典来接收**kwargs的值
5.输出注释:__doc__
@wraps()要写在闭包函数里面,并且与内嵌函数中间不能有任何代码
import time
from functools import wraps
def otter(fun):
print('xxx')
@wraps(fun) # @wraps()与内嵌函数之间不能有其他代码
# print('xxx') # 会报错
def inner(*args, **kwargs):
start = time.time()
ret = fun(*args, **kwargs)
end = time.time()
print(end - start)
return ret
return inner
@otter
def func(*args, **kwargs):
'''
这是一个很牛的方法
:param args: 接收多个位置参数
:param kwargs: 接收多个关键字参数
:return: 返回内容
'''
for i in range(1000000):
pass
return args, kwargs
ret = func('hello', name='zs', age=23)
print(ret)
print(func.__doc__)
# xxx
# 0.015600204467773438
# (('hello',), {'name': 'zs', 'age': 23})
#
# 这是一个很牛的方法
# :param
# args: 接收多个位置参数
# :param
# kwargs: 接收多个关键字参数
# :return: 返回内容
6.添加两个装饰器
多个装饰器的执行顺序:从下往上(从内往外)
from functools import wraps
import time
def wrapper1(func):
def inner1():
print('wrapper1...start')
func()
print('wrapper1...end')
return inner1
def wrapper2(func):
def inner2():
print('wrapper2...start')
func()
print('wrapper2...end')
return inner2
@wrapper1 # 等价于:inner1=wrapper1(inner2)
@wrapper2 # 等价于:inner2=wrapper2(func)
# 执行顺序:
# 1.inner2=wrapper2(func)
# 2.inner1=wrapper1(inner2)
def func():
print('func...')
func()
# wrapper1...start
# wrapper2...start
# func...
# wrapper2...end
# wrapper1...end
7.内置装饰器: @property
(1)作用:
把类的方法当属性用,更加模糊了函数与变量的调用
(2)注意:
使用@property,方法中不能有参数
# 正常代码:
from math import pi
class Circle:
def __init__(self, r):
self.r = r
def zhouchang(self):
return 2 * pi * self.r
def area(self):
return pi * self.r * self.r
c1 = Circle(2)
print(c1.zhouchang())
print(c1.area())
# 使用 @property
# 把方法当属性用
from math import pi
class Circle:
def __init__(self, r):
self.r = r
@property
def zhouchang(self):
return 2 * pi * self.r
@property
def area(self):
return pi * self.r * self.r
c1 = Circle(3)
print(c1.zhouchang) # 18.84955592153876
print(c1.area) # 28.274333882308138
(3)类中的某些属性被封装之后,想在类外改变属性的值,做法如下:
-
在你想要操作的方法前面写: @property
-
@属性.setter 后面写你想对私有变量进行的操作
-
通过:对象名.属性=值,修改私有属性的值
# 在类外改变私有属性的值
# @property
# @属性.setter
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
@property
def name(self):
return self.__name
@property
def age(self):
return self.__age
@age.setter # @属性.setter 是@property的副产品
def age(self, age):
if age < 0 or age > 150:
print('火星来的吧...')
return
self.__age = age
def __str__(self):
msg = '{}今年{}岁了'.format(self.__name, self.__age)
return msg
person = Person('zs', 12)
print(person) # zs今年12岁了
# 对象.属性=值
person.age = 20
print(person) # zs今年20岁了
print(person.name) # zs
print(person.age) # 20