【问题标题】:Class Decorator to Pre-Process kwargs for Other Class Methods为其他类方法预处理 kwargs 的类装饰器
【发布时间】:2020-12-09 04:05:51
【问题描述】:

我的CurrencyTools 类中有一套方法,我希望能够接受kwarg 不同货币缩写的输入。例如,我希望每个方法都接受“usd”或“eur”kwarg 参数。然而,为了进行计算,函数需要输入以美元为单位,因此每个方法的第一行都是使用self.convert_to_usd() 将非美元货币输入转换为美元。这个转换步骤似乎是重复的。如何创建一个调用类方法self.convert_to_usd 的装饰器来自动执行此转换“预处理”步骤并将转换后的美元金额传递给方法?我不确定装饰器如何到达self 来调用self.convert_to_usd 方法。

class CurrencyTools(object):
   def __init__(self, eurusd_exchange_rate):
      self.eurusd_exchange_rate = eurusd_exchange_rate

   def convert_to_dollars(): 
   #### ?? Decorator ?? ####

   @convert_to_dollars
   def do_calculation(self, **kwargs):
      # usd = self.convert_to_usd(**kwargs) if 'usd' not in kwargs.keys() else kwargs['usd']
      # decorator avoids repeating the line above at the start of every function
      # do calculation with usd

   def convert_to_usd(self, **kwargs):
      return kwargs['eur'] * self.eurusd_exchange_rate

# example use
CurrencyTools(eurusd_exchange_rate=1.1).do_calculation(eur=100)

【问题讨论】:

  • 类装饰器是一个可调用对象,它接受给定的class 对象作为参数并返回另一个class 对象(通常是它所传递对象的修改版本)。我认为您想要的只是一个常规函数(或方法)装饰器,其第一个参数是函数(或方法)。

标签: python class decorator


【解决方案1】:

装饰器可以用自己设计的另一个函数替换被装饰的方法。新的包装函数可以有一个self 参数,并且使方法获取实例作为第一个参数自动传递给它们的 Python 机制将像正常一样工作。只有当您将 self 传递给原始函数时,您才需要显式地传递它。

我怀疑你想要这样的东西:

def autoconvert_decorator(method):
    def wrapper(self, *args, eur=None, usd=None, **kwargs): # self gets provided like normal
        if usd is None:
            usd = self.convert_to_usd(eur=eur)
        return method(self, *args, usd=usd, **kwargs) # we have to explicitly pass self here
    return wrapper

您可以稍微改变一下以继续从kwargs 中找出usd 和/或eur 关键字参数,但我认为如果您在包装函数的签名中明确命名它们,代码会更清晰.

【讨论】:

  • 请尽可能使用@functools.wraps(method) 保留文档和其他函数元数据。
  • @TadhgMcDonald-Jensen:在这种情况下有点棘手,因为装饰器可以被视为以一种小的方式更改方法的签名(为某些关键字参数添加默认值)。对于在**kwargs 中有很多必需内容的提问者的方法,我想这还不错,尽管我建议命名参数(即使仅关键字)更好。
  • 是的,抱歉,我不一定要解决您的答案,只是为不知道 wraps 存在的其他人添加,如果毫无疑问适用,我会编辑答案。即使注释不适用,保留名称和文档也是有用的元数据,可能使用@functools.wraps(method, ['__module__', '__name__', '__qualname__', '__doc__']) 所以注释不会被保留?我不确定,无论哪种方式,我相信任何使用包装器的答案至少应该提到functools.wraps,祝你有美好的一天:)
猜你喜欢
  • 2020-12-03
  • 2014-01-14
  • 2021-08-19
  • 2016-10-14
  • 1970-01-01
  • 2020-01-11
  • 1970-01-01
  • 2014-02-18
相关资源
最近更新 更多