• 售前

  • 售后

热门帖子
入门百科

python 装饰器重要在哪

[复制链接]
123457321 显示全部楼层 发表于 2021-10-25 19:43:05 |阅读模式 打印 上一主题 下一主题
1.什么是装饰器?

要理解什么是装饰器,您起首必要熟悉Python处理函数的方式。从它的观点来看,函数和对象没有什么差别。它们有属性,可以重新分配:
  1. def func():
  2. print('hello from func')
  3. func()
  4. > hello from func
  5. new_func = func
  6. new_func()
  7. > hello from func
  8. print(new_func.__name__)
  9. > func
复制代码
别的,你还可以将它们作为参数传递给其他函数:
  1. def func():
  2. print('hello from func')
  3. def call_func_twice(callback):
  4. callback()
  5. callback()
  6. call_func_twice(func)
  7. > hello from func
  8. > hello from func
复制代码
现在,我们介绍装饰器。装饰器(decorator)用于修改函数或类的行为。实现这一点的方法是定义一个返回另一个函数的函数(装饰器)。这听起来很复杂,但是通过这个例子你会理解全部的东西:
  1. def logging_decorator(func):
  2. def logging_wrapper(*args, **kwargs):
  3. print(f'Before {func.__name__}')
  4. func(*args, **kwargs)
  5. print(f'After {func.__name__}')
  6. return logging_wrapper
  7. @logging_decorator
  8. def sum(x, y):
  9. print(x + y)
  10. sum(2, 5)
  11. > Before sum
  12. > 7
  13. > After sum
复制代码
让我们一步一步来:
      
  • 起首,我们在第1行定义logging_decorator函数。它只担当一个参数,也就是我们要修饰的函数。  
  • 在内部,我们定义了另一个函数:logging_wrapper。然后返回logging_wrapper,并使用它来代替原来的修饰函数。  
  • 在第7行,您可以看到怎样将装饰器应用到sum函数。  
  • 在第11行,当我们调用sum时,它不仅仅调用sum。它将调用logging_wrapper,它将在调用sum之前和之后纪录日志。
2.为什么必要装饰器

这很简朴:可读性。Python因其清楚简便的语法而备受赞誉,装饰器也不例外。如果有任何行为是多个函数共有的,那么您可能必要制作一个装饰器。下面是一些可能会派上用场的例子:
      
  • 在运行时检查实参范例  
  • 基准函数调用  
  • 缓存功能的结果  
  • 计数函数调用  
  • 检查元数据(权限、脚色等)  
  • 元编程
和更多…
现在我们将列出一些代码示例。
3.例子

带有返回值的装饰器
假设我们想知道每个函数调用必要多长时间。而且,函数大多数时候都会返回一些东西,所以装饰器也必须处理它:
  1. def timer_decorator(func):
  2. def timer_wrapper(*args, **kwargs):
  3. import datetime  
  4. before = datetime.datetime.now()  
  5. result = func(*args,**kwargs)
  6. after = datetime.datetime.now()  
  7. print "Elapsed Time = {0}".format(after-before)
  8. return result
  9. @timer_decorator
  10. def sum(x, y):
  11. print(x + y)
  12. return x + y
  13. sum(2, 5)
  14. > 7
  15. > Elapsed Time = some time
复制代码
可以看到,我们将返回值存储在第5行的result中。但在返回之前,我们必须完成对函数的计时。这是一个没有装饰者就不可能实现的行为例子。
带有参数的装饰器
偶尔候,我们想要一个担当值的装饰器(比如Flask中的@app.route('/login'):
  1. def permission_decorator(permission):
  2. def _permission_decorator(func):
  3. def permission_wrapper(*args, **kwargs):
  4. if someUserApi.hasPermission(permission):
  5. result = func(*args, **kwargs)
  6. return result
  7. return None
  8. return permission wrapper
  9. return _permission_decorator
  10. @permission_decorator('admin')
  11. def delete_user(user):
  12. someUserApi.deleteUser(user)
复制代码
为了实现这一点,我们定义了一个额外的函数,它担当一个参数并返回一个装饰器。
带有类的装饰器
使用类代替函数来修饰是可能的。唯一的区别是语法,所以请使用您更熟悉的语法。下面是使用类重写的日志装饰器:
  1. class Logging:
  2. def __init__(self, function):
  3. self.function = function
  4. def __call__(self, *args, **kwargs):
  5. print(f'Before {self.function.__name__}')
  6. self.function(*args, **kwargs)
  7. print(f'After {self.function.__name__}')
  8. @Logging
  9. def sum(x, y):
  10. print(x + y)
  11. sum(5, 2)
  12. > Before sum
  13. > 7
  14. > After sum
复制代码
如许做的利益是,您不必处理嵌套函数。你所必要做的就是定义一个类并覆盖__call__方法。
装饰类
偶尔,您可能想要修饰类中的每个方法。你可以如许写
  1. class MyClass:
  2. @decorator
  3. def func1(self):
  4. pass
  5. @decorator
  6. def func2(self):
  7. pass
复制代码
但如果你有许多方法,这可能会失控。值得光荣的是,有一种方法可以一次性装饰整个班级:
  1. def logging_decorator(func):
  2. def logging_wrapper(*args, **kwargs):
  3. print(f'Before {func.__name__}')
  4. result = func(*args, **kwargs)
  5. print(f'After {func.__name__}')
  6. return result
  7. return logging_wrapper
  8. def log_all_class_methods(cls):
  9. class NewCls(object):
  10. def __init__(self, *args, **kwargs):
  11. self.original = cls(*args, **kwargs)
  12. def __getattribute__(self, s):
  13. try:
  14. x = super(NewCls,self).__getattribute__(s)
  15. except AttributeError:
  16. pass
  17. else:
  18. return x
  19. x = self.original.__getattribute__(s)
  20. if type(x) == type(self.__init__):
  21. return logging_decorator(x)  
  22. else:
  23. return x
  24. return NewCls
  25. @log_all_class_methods
  26. class SomeMethods:
  27. def func1(self):
  28. print('func1')
  29. def func2(self):
  30. print('func2')
  31. methods = SomeMethods()
  32. methods.func1()
  33. > Before func1
  34. > func1
  35. > After func1
复制代码
现在,不要惊慌。这看起来很复杂,但逻辑是一样的:
      
  • 起首,我们让logging_decorator保持原样。它将应用于类的全部方法。  
  • 然后我们定义一个新的装饰器:log_all_class_methods。它类似于平凡的装饰器,但却返回一个类。  
  • NewCls有一个自定义的__getattribute__。对于对原始类的全部调用,它将使用logging_decorator装饰函数。
内置的修饰符
您不仅可以定义本身的decorator,而且在尺度库中也提供了一些decorator。我将列出与我一起工作最多的三个人:
@property -一个内置插件的装饰器,它允许你为类属性定义getter和setter。
@lru_cache - functools模块的装饰器。它记忆函数参数和返回值,这对于纯函数(如阶乘)很方便。
@abstractmethod——abc模块的装饰器。指示该方法是抽象的,且缺少实现细节。
以上就是python 装饰器告急在哪的具体内容,更多关于python 装饰器的资料请关注草根技术分享其它相干文章!

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作