Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 可作为类方法或实例方法调用的函数_Python_Function_Methods_Class Method_Instance Methods - Fatal编程技术网

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

Python 可作为类方法或实例方法调用的函数,python,function,methods,class-method,instance-methods,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()方法,该方法可以访问self及其属性: class Foo: def __init__(self, y=3): self.y = y def b

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

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

Foo.bar(7)  # prints '10'
现在我想用一些状态来改进这个接口,这样调用者就可以创建一个
Foo
对象,给它一些属性,然后调用它的
bar()
方法,该方法可以访问
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()缺少1个必需的位置参数:“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(…)
,则创建一个新的
Foo
对象(不使用参数构造函数),并将其作为
self
参数传递

我本打算亲自查看
@classmethod
的源代码来尝试这一点,但它看起来是在C级实现的。

这一节完整地介绍了
@classmethod
@staticmethod
的工作原理,以及如何在它们上实现变体,将此纯Python等效于
classmethod

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。我想先介绍一下与方法相关的东西,这可能有助于克服HOWTO第一部分的抽象困难。

标记为“完全重复”的问题是不同的——用我的话来说,就是如何获得
Foo(20.bar)
Foo.bar(20.7)
,使其表现相同,我的是关于
Foo.bar(7)
Foo.bar(7)
。区别很重要,因为整个要点是保持现有的接口
Foo.bar(7)
。刚刚实现-尽管问题不同,@user2357112的解决方案也包括我问题的解决方案。明天上班的时候我会试试看。谢谢,我会努力解决这个问题,看看能不能想出点什么办法。如果我这样做了,我会把它作为一个新的答案发布。