zoukankan      html  css  js  c++  java
  • Python装饰器详解

      1 #!/usr/bin/env python
      2 # -*- coding: utf-8 -*-
      3 """
      4                                                     __----~~~~~~~~~~~------___
      5                                    .  .   ~~//====......          __--~ ~~
      6                    -.            \_|//     |||\  ~~~~~~::::... /~
      7                ___-==_       _-~o~  /    |||  \            _/~~-
      8         __---~~~.==~||=_    -_--~/_-~|-   |\   \        _/~
      9     _-~~     .=~    |  \-_    '-~7  /-   /  ||          /
     10   .~       .~       |   \ -_    /  /-   /   ||         /
     11  /  ____  /         |     \ ~-_/  /|- _/   .||        /
     12  |~~    ~~|--~~~~--_      ~==-/   | ~--===~~        .
     13           '         ~-|      /|    |-~~~       __--~~
     14                       |-~~-_/ |    |   ~\_   _-~            /
     15                            /       \__   /~                \__
     16                        _--~ _/ | .-~~____--~-/                  ~~==.
     17                       ((->/~   '.|||' -_|    ~~-/ ,              . _||
     18                                  -_     ~      ~~---l__i__i__i--~~_/
     19                                  _-~-__   ~)  --______________--~~
     20                                //.-~~~-~_--~- |-------~~~~~~~~
     21                                       //.-~~~--
     22                                神兽保佑
     23                               代码无BUG!
     24 
     25 """
     26 
     27 # import heartrate
     28 #
     29 # heartrate.trace(browser=True)
     30 
     31 # 01. 最简单的装饰器
     32 '''
     33 def decorator(func):
     34     def wrapper(*args, **kw):
     35         return func()
     36     return wrapper
     37 
     38 @decorator
     39 def function():
     40     print("hello, decorator")
     41 
     42 
     43 function()
     44 '''
     45 
     46 # 02. 日志打印器
     47 '''
     48 def decorator(func):
     49     def wrapper(*args, **kwargs):
     50         print('开始准备执行:{}函数了'.format(func.__name__))
     51 
     52         # 真正的执行函数
     53         func(*args, **kwargs)
     54 
     55         print('{}函数执行完毕'.format(func.__name__))
     56 
     57     return wrapper
     58 
     59 
     60 @decorator
     61 def add(x, y):
     62     print('{} + {} = {}'.format(x, y, x + y))
     63 
     64 
     65 add(5, 7)
     66 '''
     67 
     68 # 03. 时间计时器
     69 '''
     70 import time
     71 
     72 
     73 def timer(func):
     74     def wrapper(*args, **kw):
     75         t1 = time.time()
     76         # 这是函数真正执行的地方
     77         func(*args, **kw)
     78         t2 = time.time()
     79 
     80         # 计算下时长
     81         cost_time = t2 - t1
     82         print("花费时间:{}秒".format(cost_time))
     83 
     84     return wrapper
     85 
     86 
     87 @timer
     88 def want_sleep(sleep_time):
     89     time.sleep(sleep_time)
     90 
     91 
     92 want_sleep(10)
     93 '''
     94 
     95 # 04. 带参数的函数装饰器 (注意,是装饰器带参数,装饰器修饰的函数不带参数)
     96 # 在原有函数装饰器的基础上外面再套一层函数
     97 '''
     98 def say_hello(contry):
     99     def wrapper(func):
    100         def deco(*args, **kwargs):
    101             if contry == "china":
    102                 print("你好!")
    103             elif contry == "america":
    104                 print('hello.')
    105             else:
    106                 return
    107 
    108             # 真正执行函数的地方
    109             func(*args, **kwargs)
    110 
    111         return deco
    112 
    113     return wrapper
    114 
    115 
    116 # 小明,中国人
    117 @say_hello("china")
    118 def xiaoming():
    119     pass
    120 
    121 
    122 # jack,美国人
    123 @say_hello("america")
    124 def jack():
    125     pass
    126 
    127 
    128 xiaoming()
    129 print("------------")
    130 jack()
    131 '''
    132 
    133 # 05. 高阶:不带参数的类装饰器 (装饰器修饰的函数带参数)
    134 """
    135 基于类装饰器的实现,必须实现 __call__ 和 __init__两个内置函数。
    136 __init__ :接收被装饰函数
    137 __call__ :实现装饰逻辑。
    138 """
    139 
    140 """
    141 class logger():
    142     def __init__(self, func):
    143         self.func = func
    144 
    145     def __call__(self, *args, **kwargs):
    146         print("[INFO]: the function {func}() is running..." 
    147               .format(func=self.func.__name__))
    148         return self.func(*args, **kwargs)
    149 
    150 
    151 @logger
    152 def say(something):
    153     print("say {}!".format(something))
    154 
    155 
    156 say("hello")
    157 """
    158 
    159 # 06. 高阶:带参数的类装饰器 (注意:类装饰器带参数,装饰的函数也带参数)
    160 
    161 """
    162 带参数和不带参数的类装饰器有很大的不同。
    163 __init__ :不再接收被装饰函数,而是接收传入参数。
    164 __call__ :接收被装饰函数,实现装饰逻辑。
    165 """
    166 
    167 """
    168 class logger():
    169     def __init__(self, level='INFO'):
    170         self.level = level
    171 
    172     def __call__(self, func):  # 接受函数
    173         def wrapper(*args, **kwargs):
    174             print("[{level}]: the function {func}() is running..." 
    175                   .format(level=self.level, func=func.__name__))
    176             func(*args, **kwargs)
    177 
    178         return wrapper  # 返回函数
    179 
    180 
    181 @logger(level='WARNING')
    182 def say(something):
    183     print("say {}!".format(something))
    184 
    185 
    186 say("hello")
    187 """
    188 
    189 # 07. 使用偏函数与类实现装饰器
    190 
    191 """
    192 绝大多数装饰器都是基于函数和闭包实现的,但这并非制造装饰器的唯一方式。
    193 
    194 事实上,Python 对某个对象是否能通过装饰器( @decorator)形式使用只有一个要求:decorator 必须是一个“可被调用(callable)的对象。
    195 
    196 对于这个 callable 对象,我们最熟悉的就是函数了。
    197 
    198 除函数之外,类也可以是 callable 对象,只要实现了__call__ 函数(上面几个例子已经接触过了)。
    199 
    200 还有容易被人忽略的偏函数其实也是 callable 对象。
    201 
    202 接下来就来说说,如何使用类和偏函数结合实现一个与众不同的装饰器。
    203 
    204 如下所示,DelayFunc 是一个实现了 __call__ 的类,delay 返回一个偏函数,在这里 delay 就可以做为一个装饰器。
    205 """
    206 
    207 """
    208 import time
    209 import functools
    210 
    211 
    212 class DelayFunc:
    213     def __init__(self, duration, func):
    214         self.duration = duration
    215         self.func = func
    216 
    217     def __call__(self, *args, **kwargs):
    218         print(f'Wait for {self.duration} seconds...')
    219         time.sleep(self.duration)
    220         return self.func(*args, **kwargs)
    221 
    222     def eager_call(self, *args, **kwargs):
    223         print('Call without delay')
    224         return self.func(*args, **kwargs)
    225 
    226 
    227 def delay(duration):
    228  
    229     # 装饰器:推迟某个函数的执行。
    230     # 同时提供 .eager_call 方法立即执行
    231     # 此处为了避免定义额外函数,
    232     # 直接使用 functools.partial 帮助构造 DelayFunc 实例
    233     return functools.partial(DelayFunc, duration)
    234 
    235 
    236 @delay(duration=2)
    237 def add(a, b):
    238     print(a+b)
    239     return a + b
    240 
    241 add(3,5)
    242 """
    243 
    244 """
    245 >>> add    # 可见 add 变成了 Delay 的实例
    246 <__main__.DelayFunc object at 0x107bd0be0>
    247 >>> 
    248 >>> add(3,5)  # 直接调用实例,进入 __call__
    249 Wait for 2 seconds...
    250 8
    251 >>> 
    252 >>> add.func # 实现实例方法
    253 <function add at 0x107bef1e0>
    254 """
    255 
    256 # 08. 装饰类的装饰器
    257 instances = {}
    258 
    259 
    260 def singleton(cls):
    261     def get_instance(*args, **kw):
    262         # print(cls) # <class '__main__.User'>
    263         cls_name = cls.__name__  # User
    264         print('===== 1 ====')
    265         # print(instances) # {}
    266         if not cls_name in instances:
    267             print('===== 2 ====')
    268             instance = cls(*args, **kw)
    269             instances[cls_name] = instance
    270         return instances[cls_name]
    271 
    272     return get_instance
    273 
    274 
    275 @singleton
    276 class User:
    277     _instance = None
    278 
    279     def __init__(self, name):
    280         print('===== 3 ====')
    281         self.name = name
    282 
    283 
    284 u1 = User("Tom")
    285 """
    286 ===== 1 ====
    287 ===== 2 ====
    288 ===== 3 ====
    289 """
    290 
    291 u1.age = 20
    292 
    293 u2 = User("Lily")
    294 """
    295 ===== 1 ====
    296 """
    297 
    298 print(u2.age)  # 20
    299 
    300 print(u1 == u2)  # True
    301 
    302 
    303 # 09. wraps 装饰器
    304 def wrapper(func):
    305     print(func.__name__)  # wrapped
    306 
    307     def inner_function():
    308         pass
    309 
    310     return inner_function
    311 
    312 
    313 @wrapper
    314 def wrapped():
    315     print('3')
    316 
    317 
    318 print(wrapped.__name__)  # inner_function
    319 print(wrapper(wrapped).__name__)  # inner_function
    320 '''
    321 上边执行func 和下边 decorator(func)  是等价的,所以上面 func.__name__ 是等价于下面decorator(func).__name__ 的
    322 '''
    323 
    324 # 使用 functools .wraps 装饰器,将 被修饰的函数(wrapped) 的一些属性值赋值给 修饰器函数(wrapper)
    325 from functools import wraps
    326 
    327 
    328 def wrapper(func):
    329     print(func.__name__)  # wrapped
    330 
    331     @wraps(func)
    332     def inner_function():
    333         pass
    334 
    335     return inner_function
    336 
    337 
    338 @wrapper
    339 def wrapped():
    340     pass
    341 
    342 
    343 print(wrapped.__name__)  # wrapped
    344 
    345 """
    346 准确点说,wraps 其实是一个偏函数对象(partial),源码如下
    347 
    348 def wraps(wrapped,
    349           assigned = WRAPPER_ASSIGNMENTS,
    350           updated = WRAPPER_UPDATES):
    351     return partial(update_wrapper, wrapped=wrapped,
    352                    assigned=assigned, updated=updated)
    353 """
    354 
    355 """
    356 可以看到wraps其实就是调用了一个函数update_wrapper,改写上面的代码,在不使用 wraps的情况下,也可以让 wrapped.__name__ 打印出 wrapped
    357 """
    358 from functools import update_wrapper
    359 
    360 WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
    361                        '__annotations__')
    362 
    363 
    364 def wrapper(func):
    365     def inner_function():
    366         pass
    367 
    368     update_wrapper(inner_function, func, assigned=WRAPPER_ASSIGNMENTS)
    369     return inner_function
    370 
    371 
    372 @wrapper
    373 def wrapped():
    374     pass
    375 
    376 
    377 print('---')
    378 print(wrapped.__name__)
    379 
    380 
    381 # 10. 内置装饰器:property
    382 # 通常存在于类中,可以将一个函数定义成一个属性,属性的值就是该函数return的内容,同时,会将这个函数变成另外一个装饰器
    383 class Student(object):
    384     def __init__(self, name):
    385         self.name = name
    386         self.name = None
    387 
    388     @property
    389     def age(self):
    390         return self._age
    391 
    392     @age.setter
    393     def age(self, value):
    394         if not isinstance(value, int):
    395             raise ValueError('输入不合法:年龄必须为数值!')
    396         if not 0 < value < 100:
    397             raise ValueError('输入不合法:年龄范围必须0-100')
    398         self._age = value
    399 
    400     @age.deleter
    401     def age(self):
    402         del self._age
    403 
    404 
    405 xiaoming = Student("小明")
    406 
    407 # 设置属性
    408 xiaoming.age = 25
    409 
    410 # 查询属性
    411 print(xiaoming.age)
    412 
    413 # 删除属性
    414 del xiaoming.age
    415 
    416 # 11. 其他装饰器:装饰器实战
    417 import signal
    418 
    419 
    420 class TimeoutException(Exception):
    421     def __init__(self, error='Timeout waiting for response from Cloud'):
    422         Exception.__init__(self, error)
    423 
    424 
    425 def timeout_limit(timeout_time):
    426     def wraps(func):
    427         def handler(signum, frame):
    428             raise TimeoutException()
    429 
    430         def deco(*args, **kwargs):
    431             signal.signal(signal.SIGALRM, handler)
    432             signal.alarm(timeout_time)
    433             func(*args, **kwargs)
    434             signal.alarm(0)
    435 
    436         return deco
    437 
    438     return wraps

     

  • 相关阅读:
    mouse_event模拟鼠标滚轮
    润乾报表配置技术路线
    建筑 物件 开心背单词 读句子,单词,字母,看图例, 翻译,看动画
    文字过渡动画,曲线过渡动画,,使用这个插件assign shape keys
    运动锻炼 开心背单词 读句子,单词,字母,看图例, 翻译,看动画,学英语,轻松背单词,简单背单词
    blender293 内置插件 精度绘画控件,PDT学习003,pdt tangents 切线
    日常用品 背单词 读句子 看图片 读单词 读字母 翻译, 看动画 学英语
    blender293 内置插件 精度绘画控件,PDT学习 precision drawing tools
    乔布斯 背单词 02 读句子 单词 字母 翻译,看动画 学英语 名言 我菜顾我在,我菜故我在,blender加python
    狐狸 和 乌鸦 英语 朗读句子 背单词
  • 原文地址:https://www.cnblogs.com/sanduzxcvbnm/p/11466104.html
Copyright © 2011-2022 走看看