【问题标题】:How to reference a class method in a class attribute?如何在类属性中引用类方法?
【发布时间】:2014-02-23 17:06:07
【问题描述】:

在一个包中,我隔离了一组在一个类中完全起作用的函数/变量。由于这些函数不需要特定的上下文,因此它们成为类方法。他们可能会使用一些外部函数,这里用save_c 函数表示。但我无法让以下代码工作:

def save_c(v):
    print("c :" + v)


class Writer(object):

    @classmethod
    def save(cls, t, v):
        cls.writers[t](v)


    @classmethod
    def save_a(cls, v):
        print("a :" + v)


    @classmethod
    def save_b(cls, v):
        print("b :" + v)

    writers = [save_a, save_b, save_c]


if __name__ == "__main__":
    Writer.save(1, [1, 2, 3])

之前的代码导致如下错误:

TypeError: 'classmethod' object is not callable

有人知道我正在尝试做的事情是否可以访问吗?还是我必须使用常规方法并在需要的地方实例化 Writer?

【问题讨论】:

    标签: python class-method class-attribute


    【解决方案1】:

    您还可以通过添加一个更智能的包装类来使其工作,该类更智能地处理它正在处理的调用。

    由于您在评论中提到您将需要调用writers多个地方之一,我已经更新了我的答案以通过添加嵌套包装类来封装逻辑在一个地方调用各种可调用类型。这是使用 OOP 应用DRY 原则的经典示例。

    def save_c(v):
        print("c :" + v)
    
    class Writer(object):
        @classmethod
        def save(cls, t, v):
            cls.writers[t](cls, v)
    
        @classmethod
        def save_a(cls, v):
            print("a :" + v)
    
        @staticmethod
        def save_b(v):
            print("b :" + v)
    
        def _wrapper(writer):
            if isinstance(writer, classmethod):
                return type('ClassmethodWrapper', (object,), {'__call__':
                            lambda self, cls, v: writer.__func__(cls, str(v))})()
            elif isinstance(writer, staticmethod):
                return type('StaticmethodWrapper', (object,), {'__call__':
                            lambda self, cls, v: writer.__func__(str(v))})()
            else:
                return type('VanillaWrapper', (object,), {'__call__':
                            lambda self, cls, v: writer(str(v))})()
    
        writers = list(map(_wrapper, (save_a, save_b, save_c)))
    
    if __name__ == "__main__":
        Writer.save(0, [1, 2, 3])  # -> a :[1, 2, 3]
        Writer.save(1, [4, 5, 6])  # -> b :[4, 5, 6]
        Writer.save(2, [7, 8, 9])  # -> c :[7, 8, 9]
    

    【讨论】:

    • 我喜欢你的回答。但是如果我需要在多个地方使用writers[t] 技巧,代码就会变得很长。
    【解决方案2】:

    实际上,内部writers 属性必须引用类方法的__func__ 属性。是的,我们需要在这里使用 staticmethod 装饰器而不是 classmethod 装饰器,以尊重用于外部调用的相同签名。以下代码运行良好:

    def save_c(v):
        print("c :" + v)
    
    
    class Writer(object):
    
        @staticmethod
        def save(t, v):
            Writer.writers[t](str(v))
    
    
        @staticmethod
        def save_a(v):
            print("a :" + v)
    
    
        @staticmethod
        def save_b(v):
            print("b :" + v)
    
        writers = [save_a.__func__, save_b.__func__, save_c]
    
    
    if __name__ == "__main__":
        Writer.save(0, [1, 2, 3])
        Writer.save(1, [1, 2, 3])
        Writer.save(2, [1, 2, 3])
    

    【讨论】:

      【解决方案3】:

      听起来您打算使用@staticmethod 而不是@classmethod

      欲了解更多信息,请参阅What is the difference between @staticmethod and @classmethod in Python?

      【讨论】:

      • staticmethod 替换classmethod 装饰器,用cls 前缀替换Writer 会导致非常相似的制裁:TypeError: 'staticmethod' object is not callable。所以这并不像看起来那么容易:P。
      • @GuillaumeLemaître:没有人说这是你必须做的全部。这只是我认为(并且仍然认为)正确方向的指针。
      • 尽管正如我的评论指出的那样,考虑到这里的真正问题,您必须承认您的回答并不是很有帮助。 @martineau 的回答更有意义。至少,这是我的看法。
      猜你喜欢
      • 1970-01-01
      • 2015-01-13
      • 2015-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多