Python | 不同下划线的区别

Python中下划线的区别

网上关于下划线的说法不一,主要有两类,总结比较如下:

其一

Python 用下划线作为变量前缀和后缀指定特殊变量

  • _xxx 不能用’from module import *’导入

  • _xxx_ 系统定义名字

  • __xxx 类中的私有变量名

核心风格:避免用下划线作为变量名的开始。

一般来讲,变量名_xxx被看作是“私有 的”,在模块或类外不可以使用。当变量是私有的时候,用_xxx 来表示变量是很好的习惯。因为变量名__xxx__对Python 来说有特殊含义,对于普通的变量应当避免这种命名风格。

“单下划线” 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量;
“双下划线” 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。

以单下划线开头(_foo)的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用“from xxx import *”而导入;

以双下划线开头的(__foo__)代表类的私有成员;以双下划线开头和结尾的(__foo__)代表python里特殊方法专用的标识,如 __init__()代表类的构造函数。

其二

单下划线开头

加了单下划线,通常认为它表示该方法或者属性是该类型的私有方法或属性。其实,在Python中不存在真正意义上的私有方法或者属性,前面加单下划线_只是表示你不应该去访问这个方法或者属性,因为它不是API的一部分。

Python
class BaseForm(StrAndUnicode):
 ...
 
 def _get_errors(self):
 "Returns an ErrorDict for the data provided for the form"
 if self._errors is None:
 self.full_clean()
 return self._errors
 
 errors = property(_get_errors)

该代码片段来自Django源码(django/forms/forms.py)。这段代码的设计就是errors属性是对外API的一部分,如果你想获取错误详情,应该访问errors属性,而不是(也不应该)访问_get_errors方法。

双下划线开头

很多地方的说法是:Python中双下划线开头表示私有。这样理解可能也不能说错,但这不是Python设计双下划线开头的初衷和目的,Python设计此的真正目的仅仅是为了避免子类覆盖父类的方法。示例:

class A(object):
 
 def __method(self):
 print("I'm a method in class A")

 def method_x(self):
 print("I'm another method in class A\n")

 def method(self):
 self.__method()
 self.method_x()

class B(A):
 
 def __method(self):
 print("I'm a method in class B")

 def method_x(self):
 print("I'm another method in class B\n")


if __name__ == '__main__':
 
 print("situation 1:")
 a = A()
 a.method()

 b = B()
 b.method()

 print("situation 2:")
 # a.__method()
 a._A__method() 

执行结果:

situation 1:
I'm a method in class A
I'm another method in class A

I'm a method in class A
I'm another method in class B

situation 2:
I'm a method in class A

需要注意:

A类中我们定义了__method()method_xmethod()三个方法;然后我们重新定义一个类B,继承自A,并且在B类中覆写(override)了其父类的__method()和method_x方法,但是从输出结果看,B对象调用method()方法时调用了其父类A的__method()方法和自己的method_x()方法。也就是说,__method()覆写没有生效,而method_x()覆写生效了。而这也正是Python设计双下划线开头的唯一目的。

这一点也可在Python官方说明中得到答案。前面我们就说了,Python中不存在真正意义上的私有变量。对于双下划线开头的方法和属性虽然我们不能直接引用,那是因为Python默认在其前面加了前缀_类名,所以就像situation 2下面的代码,虽然我们不能用a直接访问__method(),但却可以加上前缀去访问,即_A__method()

开头结尾双下划线

一般来说像__this__这种开头结尾都加双下划线的方法表示这是Python自己调用的,你不要调用。比如我们可以调用len()函数来求长度,其实它后台是调用了__len__()方法。一般我们应该使用len,而不是直接使用__len__()

a = [1, 2, 3]
print(len(a)) 
print(a.__len__()) # 和上面等效

num = 10
print(num + 10)
print(num.__add__(10)) # 和上面等效

总结

  • 使用单下划线(_one_underline)开头表示方法不是API的一部分,不要直接访问(虽然语法上访问也没有什么问题)。
  • 使用双下划线开头(__two_underlines)开头表示子类不能覆写该方法。除非你真的知道你在干什么,否则不要使用这种方式。
  • 当你想让自己定义的对象也可以像Python内置的对象一样使用Python内置的一些函数或操作符(比如len、add、+、-、==等)时,你可以定义该类方法。
  • 当然还有些属性只在末尾加了但下划线,这仅仅是为了避免我们起的一些名字和Python保留关键字冲突,没有特殊含义。

Python中下划线完全解读
Python中单、双下划线的区别总结
Difference between _, __ and xx in Python

你可能感兴趣的:(Python | 不同下划线的区别)