函数可调用为类方法或实例方法

时间:2018-03-28 22:32:07

标签: python function methods class-method instance-methods

我有一个我之前创建的Python类,它看起来像这样:

class Foo:
  @classmethod
  def bar(cls, x):
    print(x + 3)

Foo.bar(7)  # prints '10'

现在我想用一些状态来改进这个接口,以便调用者可以创建一个Foo对象,给它一些属性,然后调用它的bar()方法,该方法可以访问{ {1}}及其属性:

self

不幸的是,这打破了之前的界面 - class Foo: def __init__(self, y=3): self.y = y def bar(self, x): print(x + self.y) Foo().bar(7) # prints '10' Foo(20).bar(7) # prints '27' 现在会提供Foo.bar(7),因为TypeError: bar() missing 1 required positional argument: 'x'是一个简单的函数参考。

我可以添加一个Foo.bar(...)装饰器来获得部分:

@classmethod

是否可以创建一个转换另一个方向的class Foo: def __init__(self, y=3): self.y = y @classmethod def bar(cls, x): self = cls() print(x + self.y) Foo.bar(7) # prints '10' Foo().bar(7) # prints '10' Foo(20).bar(7) # prints '10', but I want '27' 装饰器?具体来说 - 如果作为@flexmethod之类的实例方法调用,则不执行任何操作;如果被调用为Foo(20).bar(...)之类的类方法,则创建一个新的Foo.bar(...)对象(使用no-arg构造函数)并将其作为Foo参数传递。

我打算通过查看self的来源自己尝试一下,但看起来它是在C级实现的。

1 个答案:

答案 0 :(得分:1)

Descriptor HOWTO包含@classmethod@staticmethod如何工作的完整部分,以及如何实现它们的变体,包括与classmethod等效的纯Python:

class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, klass=None):
        if klass is None:
            klass = type(obj)
        def newfunc(*args):
            return self.f(klass, *args)
        return newfunc

如果你不明白它是如何工作的,你可能需要阅读整个HOWTO。我有a blog post试图首先介绍与方法相关的东西,这可能有助于克服HOWTO第一部分的抽象概念。