【问题标题】:Modifying a class attribute via method decorator通过方法装饰器修改类属性
【发布时间】:2012-12-02 01:07:10
【问题描述】:

我有一个如下所示的课程:

class Test(object):
    data = {}

    @add_to_data(1)
    def method_1(self, x, y):
        pass

    @add_to_data(1, 2, 3)
    def method_2(self, x, y):
        pass

    @add_to_data(5, 6, 7)
    def method_3(self, x, y):
        pass

我希望它在“导入时”类的 data 属性是:

>>> Test.data
{'method_1': [1], 'method_2': [1, 2, 3], 'method_3': [5, 6, 7]}

目前我有这个(datadefaultdict):

def add_to_data(*items):
    def decorator(func):
        for item in items:
            name = func.__name__
            cls = ??
            cls.data[name].append(item)
        return func
    return decorator

但我不知道如何获取类对象。有什么帮助吗?

【问题讨论】:

    标签: python metaprogramming


    【解决方案1】:

    它不是特别干净,但是您可以使用sys._getframe() 来检查调用范围(装饰器将在类定义的上下文中调用,其中data 是一个局部变量。

    所以应该像下面这样工作:

    import sys
    
    def add_to_data(*items):
        def decorator(func):
            name = func.__name__
            data = sys._getframe(1).f_locals.get('data')
            if data is not None:
                data.setdefault(name, []).extend(items)
            return func
        return decorator
    

    如果你不想依赖sys._getframe 或者想要更明确的东西,你可以让你的@add_to_data 函数装饰器简单地用适当的函数属性标记方法,然后使用类装饰器来构建@987654326 @dictionary 来自所有标记的方法。

    【讨论】:

    • 我没想到sys._getframe();你是对的,那会奏效的。
    • 我在阅读zope.interface 源代码时第一次看到这个技巧。这是一种技巧,装饰器的用户看起来很干净,但其他人可能难以理解其实现。
    【解决方案2】:

    你不能这样做,因为类对象还不存在。

    您可能可以通过创建具有@classmethod 的基类以用作子类中的装饰器,或者将东西存储在其他地方的装饰器以及将存储复制到类的data 属性稍后。

    嗯,真的,不知道你的实际目标是什么——以及你是使用 Py2 还是 Py3(以及你只关心 CPython 还是任何 Python)——很难知道该建议什么。

    猜你喜欢
    • 2021-03-17
    • 1970-01-01
    • 2019-08-08
    • 2018-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    相关资源
    最近更新 更多