【Python】学点装饰器(3)


接前3篇:
1、学点装饰器(1)
2、学点装饰器(2)
3、闭包学习



1. wraps装饰器

functools标准库中,提供有一个wraps装饰器,那它的用处是什么呢?看一个例子:

def wrapper(func):
    def inner_func():
        pass
    return inner_func

@wrapper
def wrapped():
    pass

print(wrapped.__name__)

运行结果:

inner_func

Process finished with exit code 0

1.1 为什么不是返回 func

因为上面执行func和下边的decorator(func)是等价的,所以上面的func.__name__是等价于下面的decorator(func).__name__的,所以名字就是inner_func

def wrapper(func):
    def inner_func():
        pass
    return inner_func
 
def wrapped():
    pass

print(wrapper(wrapped).__name__)

1.2 怎么避免?

要避免这种情况的发生的方法是,使用functools.wraps装饰器,它的作用是将被修饰的函数wrapped的一些属性值赋值给修饰器函数wrapper

from functools import wraps

def wrapper(func):
    @wraps(func)
    def inner_func():
        pass
    return inner_func

@wrapper
def wrapped():
    pass

print("wraps: {}".format(wrapped.__name__))

运行结果:

wraps: wrapped

Process finished with exit code 0

wraps其实是一个偏函数partial对象,源码如下:

def wraps(wrapped,
          assigned = WRAPPER_ASSIGNMENTS,
          updated = WRAPPER_UPDATES):
          
     return partial(update_wrapper, wrapped=wrapped,
          assigned=assigned, updated=updated)

可以看到wraps其实是调用了一个函数update_wrapper,知道原理后,可以在不使用wraps的情况下改写上面的代码,让wrapped.__name___打印出wrapped,代码如下:

from functools import update_wrapper

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                       '__annotations__')
                       
def wrapper(func):
    def inner_func():
        pass

    update_wrapper(inner_func, func, assigned=WRAPPER_ASSIGNMENTS)
    return inner_func

@wrapper
def wrapped():
    pass
    
print("update_wrapper: {}".format(wrapped.__name__))

运行结果:

update_wrapper: wrapped

Process finished with exit code 0

2. 内置装饰器:property

property是python内置的一个装饰器,它通常存在于类中,可以将一个函数定义成一个属性,属性的值就是该函数return的内容。

class StudentInfo(object):
    def __init__(self, name):
        self.name = name
        # self.name = None

    @property
    def age(self):
        print("age info is: {}={}".format(self.name, self._age))
        return self._age

    @age.setter
    def age(self, value):
        if not isinstance(value, int):
            raise ValueError("年龄必须为数值!")
        if not 0 < value < 100:
            raise ValueError("年龄范围必须在0-100")
        self._age = value

    @age.deleter
    def age(self):
        del self._age

xiaoming = StudentInfo("小明")
# 设置属性
xiaoming.age = 18
# 查询属性
xiaoming.age
# 删除属性
del xiaoming.age

@property装饰过的函数,会将一个函数定义成一个属性,属性的值就是该函数return的内容,同时会将这个函数变成另外一个装饰器,就像后面使用的@age.setter@age.deleter

  • @age.setter:使得我们可以使用xiaoming.age = 18这样的方式直接复制;
  • @age.deleter:使得我们可以使用del xiaoming.age这样的方式来删除属性;

【Python】学点装饰器(3)_第1张图片
软件测试QA的碎碎念.jpg

你可能感兴趣的:(【Python】学点装饰器(3))