【问题标题】:Python 3 class decorator which get applied to the methods应用于方法的 Python 3 类装饰器
【发布时间】:2016-03-17 16:19:23
【问题描述】:

正如标题所述,我正在寻找一种装饰类的方法,这样当我调用方法时,装饰器就会应用于该调用。这背后的主要原因将允许我捕获函数调用及其传递的参数。我不走传统装饰单个方法的原因是因为这些方法可能不会提前知道,因为这些类将通过插件扩展。我也对人们可能的其他实现持开放态度不得不解决这个问题。

from functools import wraps


def echo(fh):
    def func_wrapper(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            ret = func(*args, **kwargs)
            if ret is None:
                ret = "empty"
            fn_calls = []
            if args:
                fn_calls.append([func.__name__, args, ret])
            elif kwargs:
                fn_calls.append([func.__name__, kwargs, ret])
            else:
                raise ArgumentError
            collector(fh, fn_calls)
        return wrapper
    return func_wrapper

所以把上面的装饰器应用到一个类而不是一个方法上。

伪代码示例:

@echo(file_)
class Foo(object):
    def __init__(self):
        pass

    def bar(self, name):
        print("this is %s" % name)
-----
foo = Foo()
foo.bar("baz")

这会返回类似:['foo.bar', 'baz', 'None']

提前谢谢...

【问题讨论】:

  • 为什么是装饰器?为什么不能使用元类?
  • 我也在考虑这个问题,我只是认为装饰器会提供更干净的外观。

标签: python python-3.x metaprogramming python-decorators


【解决方案1】:

如果你不喜欢元类,你可以改用类装饰器:

import functools

def _echoit(file, func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        file.write('Echoing func %s\n' % func.__name__)
        file.write('Echoing args %\n' % args)
        file.write('Echoing kwargs %s\n' % kwargs)
        return func(*args, **kwargs)
    return wrapper

def echo(file):
    def decorator(cls):
        attrs = vars(cls)
        for k in list(attrs.keys()):
             if callable(attrs[k]):
                 attrs[k] = _echoit(attrs[k], file)
        return cls
    return decorator

@echo(file_)
class Foo(object):
    def __init__(self):
        pass

    def bar(self, name):
        print("this is %s" % name)

foo = Foo()
foo.bar("baz")

如果这适用于插件系统,则具有自定义元类的基类可能会在未来更具可扩展性,并允许您拥有需要重写的自定义抽象方法等。

【讨论】:

  • 感谢您的建议。由于您提到的原因,我正在考虑沿着元类路线走。
猜你喜欢
  • 2016-07-24
  • 1970-01-01
  • 2020-11-30
  • 2018-07-14
  • 2014-01-14
  • 2021-09-12
  • 2020-01-11
  • 2012-02-09
  • 1970-01-01
相关资源
最近更新 更多