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、双下划线开头,不可用实例来更改
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值