为什么我不能在模块级调用这个函数?

Why can I not invoke this function at module-level?

问题 [python 3.8.6]

def __foo():
    pass

class MyClass:
    @staticmethod
    def bar():
        __foo()

MyClass.bar()

结果:

NameError: name '_MyClass__foo' is not defined

观察结果

问题

分辨率

我对 python 中的命名约定有误解。

Private 方法和符号在 类 中具有 双下划线前缀 ,但模块级别的相同符号具有 单下划线前缀.

因为 任何 带有两个下划线作为前缀(而不是后缀)的名称在 class 定义语句中被破坏了。来自 the docs

“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.

Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

(强调)

最明智的事情是不要用两个下划线命名你的函数。或者,您可以这样做:

def __foo():
    pass

def bar():
    __foo()


class MyClass:
    bar = staticmethod(bar)


MyClass.bar()

或者老实说,只保留 bar 作为模块级函数。

但同样,使用两个下划线也没有多大意义。如果你想表明函数不是模块 public api 的一部分,那么你应该使用 single 下划线:

def _foo():
    pass