Python 在类主体中调用类staticmethod?

Python 在类主体中调用类staticmethod?,python,decorator,static-methods,Python,Decorator,Static Methods,当我试图从类的主体中使用静态方法,并使用内置的staticmethod函数作为装饰器定义静态方法时,如下所示: class Klass(object): @staticmethod # use as decorator def _stat_func(): return 42 _ANS = _stat_func() # call the staticmethod def method(self): ret = Klass._

当我试图从类的主体中使用静态方法,并使用内置的
staticmethod
函数作为装饰器定义静态方法时,如下所示:

class Klass(object):

    @staticmethod  # use as decorator
    def _stat_func():
        return 42

    _ANS = _stat_func()  # call the staticmethod

    def method(self):
        ret = Klass._stat_func() + Klass._ANS
        return ret
我得到以下错误:

回溯(最近一次呼叫最后一次):
文件“call_staticmethod.py”,第1行,在 类Klass(对象): Klass中第7行的文件“call_staticmethod.py” _ANS=_stat_func() TypeError:“staticmethod”对象不可调用
我理解为什么会发生这种情况(描述符绑定),可以通过在上次使用后手动将
\u stat\u func()
转换为staticmethod来解决,如下所示:

class Klass(object):

    def _stat_func():
        return 42

    _ANS = _stat_func()  # use the non-staticmethod version

    _stat_func = staticmethod(_stat_func)  # convert function to a static method

    def method(self):
        ret = Klass._stat_func() + Klass._ANS
        return ret
所以我的问题是:


是否有更好的方法,如更干净或更“Pythonic”的方法来实现这一点?

在类定义之后注入class属性如何

class Klass(object):

    @staticmethod  # use as decorator
    def stat_func():
        return 42

    def method(self):
        ret = Klass.stat_func()
        return ret

Klass._ANS = Klass.stat_func()  # inject the class attribute with static method value

staticmethod
对象显然有一个
\uuuuu func\uuuu
属性来存储原始函数(它们必须这样做)。因此,这将起作用:

class Klass(object):

    @staticmethod  # use as decorator
    def stat_func():
        return 42

    _ANS = stat_func.__func__()  # call the staticmethod

    def method(self):
        ret = Klass.stat_func()
        return ret

另一方面,尽管我怀疑staticmethod对象具有某种存储原始函数的属性,但我不知道具体细节。本着教人钓鱼而不是给他们一条鱼的精神,我做了以下工作来调查并发现这一点(Python课程中的C&P):

>>类Foo(对象):
...     @静力学方法
...     def foo():
...         返回3
...     全局z
...     z=foo
>>>z
>>>Foo.Foo
>>>主任(z)
“UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU u','uu str_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
>>>z._ufunc__

在交互式会话中进行类似的挖掘(
dir
非常有用)通常可以非常快速地解决此类问题。

这是因为staticmethod是一个描述符,需要类级属性获取来执行描述符协议并获得真正的可调用属性

从源代码:

它可以在类(例如
C.f()
)或实例上调用 (例如
C().f()
);实例被忽略,但其类除外

但不能直接从类内部定义


但正如一位评论者所提到的,这根本不是一个真正的“蟒蛇式”设计。只需使用模块级函数即可

这个解决方案怎么样?它不依赖于
@staticmethod
装饰器实现的知识。内部类StaticMethod充当静态初始化函数的容器

class Klass(object):

    class StaticMethod:
        @staticmethod  # use as decorator
        def _stat_func():
            return 42

    _ANS = StaticMethod._stat_func()  # call the staticmethod

    def method(self):
        ret = self.StaticMethod._stat_func() + Klass._ANS
        return ret

这是我喜欢的方式:

class Klass(object):

    @staticmethod
    def stat_func():
        return 42

    _ANS = stat_func.__func__()

    def method(self):
        return self.__class__.stat_func() + self.__class__._ANS
与Klass.stat_func相比,我更喜欢这个解决方案,因为它的。 让我想起了Python 3中的

但我同意其他人的看法,通常最好的选择是定义一个模块级函数

例如,使用
@staticmethod
函数,递归看起来可能不是很好(您需要在
Klass.stat\u func
内部调用
Klass.stat\u func
来打破枯燥的原则)。这是因为在静态方法中没有对
self
的引用。 有了模块级函数,一切看起来都正常。

如果“核心问题”是使用函数分配类变量,另一种选择是使用元类(这有点“恼人”和“神奇”,我同意静态方法应该可以在类内调用,但不幸的是,它不是)。通过这种方式,我们可以将行为重构为一个独立的函数,而不会使类变得混乱

class KlassMetaClass(type(object)):
    @staticmethod
    def _stat_func():
        return 42

    def __new__(cls, clsname, bases, attrs):
        # Call the __new__ method from the Object metaclass
        super_new = super().__new__(cls, clsname, bases, attrs)
        # Modify class variable "_ANS"
        super_new._ANS = cls._stat_func()
        return super_new

class Klass(object, metaclass=KlassMetaClass):
    """
    Class that will have class variables set pseudo-dynamically by the metaclass
    """
    pass

print(Klass._ANS) # prints 42

在“现实世界”中使用这种替代方案可能会有问题。我不得不用它来覆盖Django类中的类变量,但在其他情况下,也许最好使用其他答案中的一个选项。

如果你问的是Pythonicity,那么标准建议是根本不要使用
staticmethod
。它们通常作为模块级函数更有用,在这种情况下,您的问题不是问题<另一方面,code>classmethod。@poorsod:是的,我知道这个选择。然而,在我遇到这个问题的实际代码中,使函数静态化而不是将其置于模块级比在我的问题中使用的简单示例更为合理。@ CalMARL: Python不是C++,也没有保护方法。在方法名前面加上
只是一种约定,表示某些东西是私有的(尽管语言没有强制执行它),可能有也可能没有任何w.r.t.继承。无论如何,我问题中的代码只是为了说明调用静态方法的问题。@martineau没错,它只是调用约定。当简单的
\uuu
表示受保护,而双重
\uuu
表示私有。然后,正如我所说,在这种情况下,对静态方法应用protected(通过调用约定)毫无意义。@CallMarl:正如我已经指出的,代码只是我为了提出问题而拼凑起来的东西。这类似于我第一次尝试解决问题,但我更喜欢类内部的东西…部分原因是所涉及的属性有一个前导下划线并且是私有的。我可以先调用Klass.\u ANS=Klass.stat\u func()然后定义类吗?这是不允许的,当我尝试这个时,我看到一个错误类不存在?很好的更新…我正要问你是怎么知道的,因为我在文档中没有看到它-这让我有点担心使用它,因为它可能是一个“实现细节”。@martineau不在这个上下文中。绑定和未绑定的方法对象具有用于获取原始函数的
im\u func
属性,并且这些方法对象的
\uuu func
属性与
im\u func
相同
staticmethod
对象没有
im_func
属性(如my
dirclass KlassMetaClass(type(object)):
    @staticmethod
    def _stat_func():
        return 42

    def __new__(cls, clsname, bases, attrs):
        # Call the __new__ method from the Object metaclass
        super_new = super().__new__(cls, clsname, bases, attrs)
        # Modify class variable "_ANS"
        super_new._ANS = cls._stat_func()
        return super_new

class Klass(object, metaclass=KlassMetaClass):
    """
    Class that will have class variables set pseudo-dynamically by the metaclass
    """
    pass

print(Klass._ANS) # prints 42