我已经搜索了一堆,似乎无法弄清楚如何实际执行此操作:
鉴于我有一个通用的实用方法,如下:
def __square(n):
return n*n
然后我有一些类我可能想在内部使用这个方法:
def __square(n):
return n*n
class Foo:
def __init__(self):
self.baz = 2
def bar(self):
return self.baz + __square(self.baz)
嗯,这不起作用。我得到NameError '_Foo__square' is not defined
为什么?
作为一种解决方法,我最终做了这样的事情:
class Foo:
def __init__(self):
self.baz = 2
def bar(self):
return baz + self.square(self.baz)
def square(self,n):
return n*n
但这对我来说很愚蠢,因为square函数与Foo实例无关,我也不希望或希望它成为Foo实例上的方法。
" pythonic"" pythonic"处理这类事情的方式?
修改
我想出了至少一部分内容:我得到了这种行为,因为我认为这些实用程序方法是私有的,我将它们命名为def __square(n):
。
我没有意识到这很特别,在输入上面的示例时,我最初并没有这样输入。我现在编辑了这个问题,以反映它实际输入的方式。
所以现在我的问题是:为什么将__
置于顶级方法之前打破它,或者似乎?我明白这是命名和私人事物的约定。在Python中,因为它在这种情况下不起作用,你会推荐什么呢?
答案 0 :(得分:7)
您不应该在函数名前加上两个下划线 - __
- 只要在类中的代码中找到以两个下划线名称为前缀的名称,Python编译器就会执行名称重整操作。 - 因此,在编译(到字节码)时,对__square
的引用转换为对不存在的_Foo_square
的引用。
只需在_
中使用一个_square
,就不会出现此错误。
Python没有像“私人”这样的名字。按照惯例 - 仅限于约定 - 不应该从其他范围的代码中调用或访问前缀为_
的函数或属性。
有些人在互联网上写了一些文章,试图为其他广为人知的OOP语言中存在的每个概念创建等价,实际上提到双下划线前缀相当于这些语言中的“私有”变量。这是旧文档中的一个常见错误 - 最近的文章避免了这个错误。
双下划线前缀的行为有所不同 - 有时可以与private
(与protected
)属性相同的目的:它确实在操作中转换变量名称在Python的文档中称为“名称修改”。通常这用于属性名称,并且它被转换为容器类唯一的名称,默认情况下,它只能在定义的类上访问,而不能在其子类上访问。转换是确定性的并且有详细记录:一个下划线和类名称前置于属性的名称(包括两个下划线)。因此,具有Polygon
属性的__area
类在运行时实际上会有_Polygon__area
- 如果派生的class Square(Polygon):
类将尝试访问{{1}在其代码中,它实际上会在运行时访问__area
。 (但是可以通过在代码中明确地编写_Square__area
来读取和编写超类“__area
”