栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

使用类与函数的Python装饰器最佳实践

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用类与函数的Python装饰器最佳实践

说每种方法是否都具有“优势”是相当主观的。

但是,如果对幕后的事物有一个很好的了解,那么自然就可以为每种场合选择最佳选择。

装饰器(谈论函数装饰器)只是一个以函数为输入参数的可调用对象。Python有其相当有趣的设计,它允许除功能以外还可以创建其他类型的可调用对象-
并且可以将其用于创建更多可维护的或更短的代码。

装饰器在Python 2.3中作为“语法快捷方式”添加回

def a(x):   ...a = my_decorator(a)

除此之外,当我们使用这种类型时,我们通常将装饰器称为“装饰器”,而不是“装饰器工厂”。

@my_decorator(param1, param2)def my_func(...):   ...

使用param1和param2调用“ my_decorator”-然后返回将再次调用的对象,这次以“
my_func”作为参数。因此,在这种情况下,从技术上讲,“ decorator”是“ my_decorator”返回的值,从而使其成为“
decorator factory”。

现在,如上所述的装饰器或“装饰器工厂”通常必须保留一些内部状态。在第一种情况下,它唯一保留的是对原始函数的引用(

f
在示例中称为变量)。“装饰器工厂”可能想要注册其他状态变量(在上面的示例中为“
param1”和“ param2”)。

在装饰器编写为函数的情况下,此额外状态保留在封闭函数内的变量中,并由实际包装函数作为“非局部”变量进行访问。如果编写了适当的类,则可以将它们作为实例变量保存在装饰器函数(将被视为“可调用对象”,而不是“函数”)中,并且对它们的访问更加明确并且更具可读性。

因此,在大多数情况下,是否选择一种方法还是一个可读性问题:对于简短的装饰器而言,功能性方法通常比一个类编写的方法更具可读性-有时更精细-
尤其是一种“装饰工厂”将充分利用Python编码之前的“扁平优于嵌套”建议。

考虑:

def my_dec_factory(param1, param2):   ...   ...   def real_decorator(func):       ...       def wraper_func(*args, **kwargs):...#use param1result = func(*args, **kwargs)#use param2return result       return wraper_func   return real_decorator

针对这种“混合”解决方案:

class MyDecorator(object):    """Decorator example mixing class and function definitions."""    def __init__(self, func, param1, param2):        self.func = func        self.param1, self.param2 = param1, param2    def __call__(self, *args, **kwargs):        ...        #use self.param1        result = self.func(*args, **kwargs)        #use self.param2        return resultdef my_dec_factory(param1, param2):    def decorator(func):         return MyDecorator(func, param1, param2)    return decorator

更新 :缺少装饰器的“纯类”形式

现在,请注意“混合”方法采用“两全其美”的做法,以保持最短且可读性更高的代码。专门用类定义的完整“装饰器工厂”将需要两个类,或者需要一个“模式”属性来知道是否调用了它来注册修饰后的函数或实际调用了最终函数:

class MyDecorator(object):   """Decorator example defined entirely as class."""   def __init__(self, p1, p2):        self.p1 = p1        ...        self.mode = "decorating"   def __call__(self, *args, **kw):        if self.mode == "decorating":  self.func = args[0]  self.mode = "calling"  return self         # pre to run prior to function call         result = self.func(*args, **kw)         # pre to run after function call         return result@MyDecorator(p1, ...)def myfunc():    ...

最后是一个纯净的“白领”装饰器,定义了两个类-也许可以使事物更加分离,但是将冗余性提高到一定程度,这不能说它更易于维护:

class Stage2Decorator(object):    def __init__(self, func, p1, p2, ...):         self.func = func         self.p1 = p1         ...    def __call__(self, *args, **kw):         # pre to run prior to function call         ...         result = self.func(*args, **kw)         # pre to run after function call         ...         return resultclass Stage1Decorator(object):   """Decorator example defined as two classes.   No "hacks" on the object model, most bureacratic.   """   def __init__(self, p1, p2):        self.p1 = p1        ...        self.mode = "decorating"   def __call__(self, func):       return Stage2Decorator(func, self.p1, self.p2, ...)@Stage1Decorator(p1, p2, ...)def myfunc():    ...

2018更新

我几年前在上面写过文字。由于创建了“更扁平”的代码,最近我想到了一个更喜欢的模式。

基本思想是使用函数,但是

partial
如果在用作修饰符之前使用参数调用了该对象,则返回其自身的对象:

from functools import wraps, partialdef decorator(func=None, parameter1=None, parameter2=None, ...):   if not func:        # The only drawback is that for functions there is no thing        # like "self" - we have to rely on the decorator         # function name on the module namespace        return partial(decorator, parameter1=parameter1, parameter2=parameter2)   @wraps(func)   def wrapper(*args, **kwargs):        # Decorator pre-  parameter1, etc... can be used         # freely here        return func(*args, **kwargs)   return wrapper

就是这样-使用此模式编写的装饰器可以立即装饰函数,而无需先“调用”:

@decoratordef my_func():    pass

或使用参数定制:

@decorator(parameter1="example.com", ...):def my_func():    pass

2019年 -使用Python 3.8和仅位置参数,最后一个模式将变得更好,因为

func
可以将参数声明为仅位置参数,并要求对参数进行命名;

def decorator(func=None, *, parameter1=None, parameter2=None, ...):


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/651569.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号