0

在一个包中,我隔离了一组在一个类中完全起作用的函数/变量。由于这些函数不需要特定的上下文,因此它们成为类方法。他们可能会使用一些外部函数,这里用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?

4

3 回答 3

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]
于 2014-02-23T19:57:55.190 回答
1

实际上,内部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])
于 2014-02-23T17:54:17.603 回答
0

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

有关更多信息,请参阅Python 中的 @staticmethod 和 @classmethod 有什么区别?

于 2014-02-23T17:19:36.637 回答