python —— 装饰器
1、装饰器简介
- 1、函数也是一个对象,而且函数对象也可以被赋值给变量,所以通过变量也能调用该函数
- 2、函数对象有一个__name__属性,可以拿到函数的名字
- 3、装饰器的作用就是为已经存在的对象添加额外的功能
- 4、装饰器是在定义函数和类的时候使用
2、简单装饰器
实现我们在跑程序的时候告诉我们运行进度
def decorator_process(func):
def wrapper(*args,**kargs):
print("%s已经开始运行"%func.__name__)
return func(*args,**kargs)
return wrapper
@decorator_process
def wj_sum(a,b):
print(a+b)-7
wj_sum(5,6)
3、带参数的装饰器
装饰器允许我们在调用时提供给它参数
def decorator_user(user):
def decorator(func):
def wrapper(*args,**kargs):
print("%s在使用%s函数"%(user,func.__name__))
return func(*args,**kargs)
return wrapper
return decorator
@decorator_user("wj")
def wj_average(a,b):
print((a+b)/2)
wj_average(2,5)
3、类装饰器
- 相比于函数装饰器,装饰器具有灵活度大、高内聚、封装性等优点,
- 使用类装饰器还可以依靠内部的__recall__方法,
- 当使用@形式将装饰器附加到函数上时,就会调用此方法
class decorate_process_cls(object):
def __init__(self,func):
self.func = func
def __call__(self,*args,**kargs):
print("%s函数开始运行"%self.func.__name__)
self.func(*args,**kargs)
print("%s函数运行结束"%self.func.__name__)
@decorate_process_cls
def wj_mean(a,b):
print((a+b)/2)
wj_mean(2,5)
4、functools.wraps
- 使用装饰器极大地复用了代码,但是它有一个缺点就是原函数的元信息不见了;
- 这个问题就比较严重,好在我们有functools.wraps,wraps本身也是一个装饰器;
- 它能把原函数的元信息拷贝到装饰器函数中,这使得装饰函数也也有和原函数一样的元信息。
from functools import wraps
import datetime
class decorator_process_cls2(object):
def __init__(self,func):
self.func = func
def __call__(self,*args,**kargs):
"""
这是一个装饰器
"""
print(datetime.datetime.now(),"%s程序开始运行"%self.func.__name__)
self.func(*args,**kargs)
print(datetime.datetime.now(),"%s程序结束运行"%self.func.__name__)
@decorator_process_cls2
def wj_multiply(a,b):
"""
这是原函数
"""
print(a*b)
print(dir(wj_multiply))
class decorator_process_cls2(object):
def __init__(self,func):
self.func = func
@wraps
def __call__(self,*args,**kargs):
"""
这是一个装饰器
"""
print(datetime.datetime.now(),"%s程序开始运行"%self.func.__name__)
self.func(*args,**kargs)
print(datetime.datetime.now(),"%s程序结束运行"%self.func.__name__)
@decorator_process_cls2
def wj_multiply(a,b):
"""
这是原函数
"""
print(a*b)
print(dir(wj_multiply))
5、内置装饰器
- @classmethod
- @staticmethod
- @property
5.1 @classmethod
- 我们要写一个实例不能调用,而能用类调用的方法,则可添加@classmethod的装饰器
- 此时函数不需要传self这个参数,但是需要传类这个对象作为参数
class wj_1(object):
name = "张三"
age = 18
@classmethod
def infor(class_object):
print(class_object.name,"的年龄是",class_object.age,"岁",sep = "")
wj_1.infor()
5.2 @staticmethod
- 经常有一些跟类有关系的功能,但在运行时又不需要实例和类参与的情况下,
- 需要用到静态方法,比如更改环境变量或者修改其它类的属性等能用到静态方法,
- 实例或者类都能调用该方法
class wj_2(object):
def __init__(self):
self.name_ = "李四"
self.age_ = 25
name = "张三"
age = 18
@staticmethod
def update_name():
wj_2.name = "王二"
print(wj_2.name)
wj_2.update_name()
print(wj_2.name)
- 1、@staticmethod 不需要表示自身对象的self参数,也不需要表示自身类的参数class_object,就和使用函数一样
- 2、@classmethod不需要self,但是需要class_object
class wj_ensemble(object):
sign = "a处"
def __init__(self):
self.sign = "b处"
@classmethod
def func_class(class_obj):
print(class_obj.sign)
@staticmethod
def func_static():
print(wj_ensemble.sign)
def func_usual(self):
print(self.sign)
# 实例运行普通类函数
wj_ensemble().func_usual()
# 类运行普通类函数
try:
wj_ensemble.func_usual
except Exception as error:
print("类不能调用普通函数")
# 类调用@classmethod装饰的方法
wj_ensemble.func_class()
# 实例不能调用@classmethod装饰的方法
wj_ensemble().func_class()
# 静态函数都可以调用
wj_ensemble.func_static()
wj_ensemble().func_static()
5.3 @property
使用此装饰器以后,实例可以把方法当属性来调用,也就是无法对属性赋值使用,@property最主要的目的是使得对私有属性无法修改
class wj_3(object):
def __init__(self):
self.__name__ = "玫瑰少年"
@property
def name(self):
return self.__name__
wj_3().name
6、属性的分类
6.1 实例的属性
- 1、在def __ init __(self)中初始化
- 2、内部调用使用self.property
- 3、外部调用使用instance.property
6.2 类属性
- 1、在def __ init __(self)外初始化
- 2、内部调用:classname.property
- 3、外部调用:classname.property 或者 instance.property
6.3 类属性
- 1、单下划线开头,只是告诉别人这是私有属性,外部依旧可以更改
- 2、双下划线开头,不可用实例来更改