【问题标题】:Why can't I invoke a static method inside the class body?为什么我不能在类体内调用静态方法?
【发布时间】:2022-01-22 06:14:20
【问题描述】:
class StaticClass(object):
    words = []
    StaticClass.init()
    
    @staticmethod
    def init(file_name):
        ...
        words.append('word')
        ...

    @staticmethod
    def fun():
        print('fun')
            

test = StaticClass()

错误信息是:

StaticClass.init()
NameError: name 'StaticClass' is not defined

为什么不能在类中调用静态函数?

我想使用一个类来做到这一点,也希望用户能够做到:

StaticClass.fun()

如何实现效果?

【问题讨论】:

  • 你不能像那样在类的主体中使用类的名称。如果必须使用函数将words 初始化为类属性,只需在类外定义函数即可。如果您只是想捆绑一些功能,请考虑编写模块而不是类。
  • 这个错误的问题是StaticClass 没有在范围内定义,直到它的主体中的所有语句都被执行。也就是说,Python 中的类定义是执行的,而不是像 C# 或 Java 这样的“定义”。
  • @MisterMiyagi,那么我应该将它定义为实例函数吗?我希望用户可以直接使用 StaticClass.fun(),而无需先显式实例化它。
  • 只是为了确定:你的类实际上有任何实例状态吗?如果没有,通常最好使用模块。
  • 如果 StaticClass.init 必须在用户可以使用 StaticClass.fun 之前发生,那么您自己在顶层调用它,紧跟在 class 定义之后。如果用户以后也不应该再次调用它,请考虑使用前导下划线对其进行标记。但是,如果您需要来自用户的信息(例如file_name),那么您就不走运了。是的,一般而言仔细考虑为什么要使事物静态化。类作为命名空间有点笨拙。

标签: python


【解决方案1】:

为什么不能在类中调用静态函数?

如 cmets 中所述,class 主体在 Python 中执行。它就像一个自动运行一次的零参数函数;然后调用type,将类名、基类和类属性的字典传递给它来自该函数的局部变量;并且只有 then 将来自type(即类对象)的结果分配给名称。

您甚至可以在其中放置逻辑和其他语句:

import random

# a class that sometimes fails to exist when you import the module.
class spam:
    if __name__ != '__main__':
        1 / random.randrange(3)
    else:
        print("thank you for running this as the main script.")
    def __init__(self):
        # etc.

因此,名称必须在范围内。 在这段代码运行时 - 因为它立即自动运行,而不是像函数一样被延迟 - 在这段代码完成之前没有StaticClass。因此,里面的代码不能引用类本身。

要解决这个问题,只需将调用移到末尾即可:

class StaticClass(object):
    words = []
    
    @staticmethod
    def init(file_name):
        ...
        words.append('word')
        ...

    @staticmethod
    def fun():
        print('fun')

StaticClass.init()

【讨论】:

    【解决方案2】:

    StaticClass 类的主体被执行时,没有对StaticClass 的引用,它还不存在。类的主体在作为字典的命名空间内执行。之后,使用该填充字典创建一个 type 类型的新实例,此处命名为 StaticClass,并将其添加到全局命名空间中。这就是 class 关键字在简单形式中的大致作用。

    其实我不知道你为什么想让这个工作。其他人已经提出了处理它的最佳方法,但是如果您想在创建 class 时将 staticmethod 作为初始化函数调用并在类中调用它,则可以使用以下解决方法:

    class StaticClass(object):
        words = []
    
        @staticmethod
        def init(file_name, words=words):
            words.append(file_name)
    
        init.__get__(init)('word')
    
        @staticmethod
        def fun():
            print('fun')
    
    
    test = StaticClass()
    StaticClass.fun()
    print(StaticClass.words)
    

    输出:

    fun
    ['word']
    

    是的,这确实是一团糟,我只是想让它起作用来说明为什么它以前不起作用。您需要致电init.__get__,因为静态方法不可调用。 (我在 Python 3.9.7 中)这样你 init 在创建类时执行。另外words 也无法访问,因为类的范围没有包含在init 的主体范围内,所以我使用它的引用作为默认参数。

    【讨论】:

      猜你喜欢
      • 2014-07-13
      • 2011-03-02
      • 2018-09-20
      • 2018-02-15
      • 1970-01-01
      • 2015-10-07
      • 2010-11-01
      相关资源
      最近更新 更多