py装饰器(functools.wraps(func)装饰器、functools模块、@property装饰器)


"""
py装饰器.py
(functools.wraps(func)装饰器、functools模块、@property装饰器)

装饰器@(decorator装饰器 = 高阶函数 + 闭包函数)
装饰器本质上是接受一个函数作为参数(高阶函数行为),并返回一个函数(闭包函数行为)。
返回函数即子函数 中定义添加内容后 再返回主函数的参数函数。
从而实现不修改 参数函数的基础上 在代码运行期间动态增加功能的方式。

1、#使用:如果装饰器decorator本身需要传入参数,那就需要编写一个返回装饰器的高阶函数(即三层嵌套装饰器函数)。

2、#使用:functools.wraps(func)装饰器
#注意:装饰器装饰过的函数的原属性已经改变,因为装饰器内部是闭包主函数return返回了子函数。
#解决办法是 通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。

3、#深入:import functools  
#functools 模块中主要包含了一些函数装饰器和便捷的功能函数。
3.1、#使用:@functools.wraps(func)
通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。
3.2、#使用:functools.partial()用来创建一个偏函数,即把一个函数的某些参数给固定住(即设置默认值),返回一个新函数。
#注意:偏函数实质上是一个 @装饰器 的原理,即在参数列表里追加进去 设置默认值的参数。
#如:int2('1000') 实则是运行的 int('1000',base=2)


4、@property(@property装饰器为可读属性 / 装饰函数.setter装饰器为可写属性)
#使用:@property装饰器 负责把一个方法变成属性来调用,即:@property装饰器相当于getter方法可读属性。
#注意:@property装饰器 本身又会创建另一个装饰器,即:使用:装饰函数.setter装饰器 相当于 setter可写属性。

"""



################### 装饰器@(decorator装饰器 = 高阶函数 + 闭包函数)
#装饰器本质上是接受一个函数作为参数(高阶函数行为),并返回一个函数(闭包函数行为)。
#返回函数即子函数 中定义添加内容后 再返回主函数的参数函数。
#从而实现不修改 参数函数的基础上 在代码运行期间动态增加功能的方式。

#使用:functools.wraps(func)装饰器
#注意:装饰器装饰过的函数的原属性已经改变,因为装饰器内部是闭包主函数return返回了子函数。
#解决办法是 通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。
#深入:import functools  使用:@functools.wraps(func)


#####
#定义一个本身不需要传入参数的装饰器 打印日志的装饰器decorator
def log(func):
    """接收一个函数作为参数,称为高阶函数
    返回子函数,称为闭包函数"""
    def wrapper(*args,**kw):
        """返回主函数的参数函数,从而达到不修改参数函数的基础上 动态增加print功能"""
        print('开始调用函数:%s()' %func.__name__)
        """动态增加print功能后,继续调用原函数()执行"""
        return func(*args,**kw)
    return wrapper
"""使用:@decorator放到 func函数定义前,相当于执行了 func=decorator(func),重新赋值定义了一个同名新函数"""
@log    
def now():
    print('2019/11/08')
now()
"""等同于不添加装饰器@log情况下的如下表示:"""
#log(now)()
#now=log(now)
#now()


#####
#使用:如果装饰器decorator本身需要传入参数,那就需要编写一个返回装饰器的高阶函数(即三层嵌套装饰器函数)。
#定义一个本身需要传入参数的装饰 打印日志的装饰器
def log(who):
    def decorator(func):
        def wrapper(*args,**kw):
            print('%s开始调用函数:%s()' %(who,func.__name__))
            return func(*args,**kw)
        return wrapper
    return decorator
@log('小王')
def now():
    print('2019/11/09')
now()
"""等同于不添加#log('小王')的如下表示:"""
#log('小张')(now)()
#now=log('小张')(now)
#now()



#####
#使用:functools.wraps(func)装饰器
#注意:装饰器装饰过的函数的原属性已经改变,因为装饰器内部是闭包主函数return返回了子函数。
#解决办法是 通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。

#深入:import functools  
#functools 模块中主要包含了一些函数装饰器和便捷的功能函数。
#2.1、使用:@functools.wraps(func)
#通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。

import functools

def log(func):
#    @functools.wraps(func)
    def wrapper(*args,**kw):
        print('开始调用函数:%s()' %func.__name__)
        return func(*args,**kw)
    return wrapper
@log
def now():
    print('2019/11/09')
now()
print(now.__name__)

#对比添加了 @functools.wraps(func) 装饰器之后的 now.__name__

import functools

def log(who):
    def decorator(func):
        """使用:functools.wraps(func)装饰器
        通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 
        来纠正被此装饰器装饰过的func函数属性。
        """
        @functools.wraps(func)
        def wrapper(*args,**kw):
            print('%s \n %s开始调用函数:%s' %('接下来使用了functools.wraps(func)技术',who,func.__name__))
            return func(*args,**kw)
        return wrapper
    return decorator
@log('小刘')
def now():
    print('2019/11/10')
now()
now.__name__





#################### @property(@property装饰器为可读属性 / 装饰函数.setter装饰器为可写属性)
#使用:@property装饰器 负责把一个方法变成属性来调用,即:@property装饰器相当于getter方法可读属性。
#注意:@property装饰器 本身又会创建另一个装饰器,即:使用:装饰函数.setter装饰器 相当于 setter可写属性。

class Student(object):    
    """#使用:@property装饰器 负责把一个方法变成属性来调用;
    即:@property装饰器相当于getter方法可读属性。"""
    @property
    def score(self):
        return self._score
    
    """#注意:@property装饰器 本身又会创建另一个装饰器;
    即:使用:@装饰函数.setter装饰器 相当于 setter可写属性。"""
    @score.setter
    def score(self,value):
        if not isinstance(value,int):
            raise ValueError('成绩需要是个整数')
        if value<0 or value>100:
            raise ValueError('成绩需要时0~100')
        self._score=value
s=Student()
s.score=100
s.score


#当代码有了@property装饰器以后,我们就知道属性很可能不是直接暴露的,而是通过getter方式读取 和 setter方法写入的。
#定义只读属性,即:只定义@property装饰器(getter方法),补丁已setter方法。
#定义可读可写属性,即:定义@property装饰器 及 @装饰函数.setter装饰器
#如:
class Student(object):
    """定义可读可写的birth属性"""
    @property
    def birth(self):
        return self.__birth
    @birth.setter
    def birth(self,value):
        self.__birth=value
        
    """定义只读属性(无@装饰函数.setter装饰器)"""
    @property
    def age(self):
        return 2015-self.__birth











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值