类访问私有方法的最佳方式(私有名称改编)

3 投票
1 回答
532 浏览
提问于 2025-04-18 17:56

如果我有这个:

class Test:
    def __init__(self, x):
        self.x = x
    def A(self):
        __doA()

def __doA():
    print 'A'

if __name__ == '__main__':
    t = Test(1)
    t.A()

这显然会导致一个错误:NameError: global name '_Test__doA' is not defined

根据文档:

当一个在类定义中出现的标识符以两个或更多的下划线开头,并且不以两个或更多的下划线结尾时,它被认为是该类的私有名称。私有名称在生成代码之前会被转换成一个更长的形式。这个转换会在名称前面插入类名,去掉前面的下划线,并插入一个下划线。例如,在一个名为 Ham 的类中出现的标识符 __spam 会被转换成 _Ham__spam。这个转换与标识符使用的语法上下文无关。如果转换后的名称非常长(超过255个字符),可能会被截断。如果类名仅由下划线组成,则不会进行转换。

我想保留这两个下划线,因为这个模块会被很多人使用,我想表示这些方法是私有的,但我仍然希望类能够访问它们。

一个快速的解决办法是把方法名也改成以两个下划线结尾,这样就可以绕过名称混淆的问题:

class Test:
    def __init__(self, x):
        self.x = x
    def A(self):
        __doA__()

def __doA__():
    print 'A'

if __name__ == '__main__':
    t = Test(1)
    t.A()

我不确定让一个私有方法也以两个下划线结尾在 Python 中是否合适。

还有一种我认为不太优雅的方法是:

class Test:
    def __init__(self, x):
        self.x = x
        self.__doA = globals()['__doA']
    def A(self):
        self.__doA()

def __doA():
    print 'A'

if __name__ == '__main__':
    t = Test(1)
    t.A()

有没有更好的方法可以在 Python 中从类内部访问私有方法?

1 个回答

1

这里有一个简单的脚本来重现这个错误:

def __foo(x):
    print x

__foo("foo")

class Bar(object):
    def baz(self, x):
        __foo(x)


Bar().baz("foo")

这会导致:

foo # direct call works

Traceback (most recent call last):
  File "C:/Python27/test.py", line 11, in <module>
    Bar().baz("foo")
  File "C:/Python27/test.py", line 8, in baz
    __foo(x)
NameError: global name '_Bar__foo' is not defined # gets mangled in class, breaks

你不应该给函数(和方法不同)起带有双下划线开头的名字,因为这样会在你尝试从类内部访问它们时出现问题——这个函数就变得无法访问了,因为没有类名可以加在它前面。

如果你想表示一个函数是私有的,可以用一个下划线开头,但 我们都是成年人了

撰写回答