内容目录
单下划线与双下划线的区别单下划线(_)名称前的单下划线(如:_name)名称前的双下划线(如:__name)名称前后的双下划线(如:_ init _)总结
单下划线与双下划线的区别
Python用下划线作为前缀和后缀指定特殊变量和定义方法,主要有如下四种形式:
- 单下划线(_)
- 名称前的单下划线(如:_name)
- 名称前的双下划线(如:__name)
- 名称前后的双下划线(如:_ init _)
单下划线(_)
只有单划线的情况,主要有两种使用场景:
1、在交互式解释器中,单下划线“_”代表的是上一条执行语句的结果。如果单下划线前面没有语句执行,交互式解释器将会报单下划线没有定义的错误。也可以对单下划线进行赋值操作,这时单下划线代表赋值的结果。但是一般不建议对单下划线进行赋值操作,因为单下划线内建标识符。
1>>> _ 2Traceback (most recent call last): 3 File "<pyshell#0>", line 1, in <module> 4 _ 5NameError: name '_' is not defined 6>>> "python" 7'python' 8>>> _ 9'python' 10>>> _="Java" 11>>> _ 12'Java' 13>>>
2、单下划线“_”还可以作为特殊的临时变量。如果一个变量在后面不会再用到,并且不想给这个变量定义名称,这时就可以用单下划线作为临时性的变量。比如对for循环语句遍历的结果元素并不感兴趣,此时就可以用单下划线表示。
1# _ 这个变量在后面不会用到 2for _ in range(5): 3 print("Python")
名称前的单下划线(如:_name)
当在属性和方法前面加上单下划线“_”,用于指定属性和方法是“私有”的。但是Python不像Java一样具有私有属性、方法、类,在属性和方法之前加单下划线,只是代表该属性、方法、类只能在内部使用,是API中非公开的部分。如果用from import * 和 from import * 时,这些属性、方法、类将不被导入。
1# Test.py 文件 2 3#普通属性 4value="Java" 5 6#单下划线属性 7_otherValue="Python" 8 9 10#普通方法 11def method(): 12 print("我是普通方法") 13 14#单下划线方法 15def _otherMethod(): 16 print("我是单下划线方法") 17 18#普通类 19class PClass(object): 20 21 def __init__(self): 22 print("普通类的初始化") 23 24#单下划线类 25class _WClass(object): 26 27 def __init__(self): 28 print("单下划线类的初始化")
将上述的Test.py文件导入,进行测试。
1>>> from Test import * 2>>> value 3'Java' 4>>> _otherValue 5Traceback (most recent call last): 6 File "<pyshell#4>", line 1, in <module> 7 _otherValue 8NameError: name '_otherValue' is not defined 9>>> method() 10我是普通方法 11>>> _otherMethod() 12Traceback (most recent call last): 13 File "<pyshell#6>", line 1, in <module> 14 _otherMethod() 15NameError: name '_otherMethod' is not defined 16>>> p=PClass() 17普通类的初始化 18>>> w=_WClass() 19Traceback (most recent call last): 20 File "<pyshell#8>", line 1, in <module> 21 w=_WClass() 22NameError: name '_WClass' is not defined
从上面的结果可以看出,不管是属性、方法和类,只要名称前面加了单下划线,都不能导出。
如果对程序进行修改,将在开头加入_ all _,结果会是如何?
1# Test.py 文件 2 3#将普通属性、单下划线的属性、方法、和类加入__all__列表 4__all__=["value","_otherValue","_otherMethod","_WClass"] 5 6#普通属性 7value="Java" 8 9#单下划线属性 10_otherValue="Python" 11 12#普通方法 13def method(): 14 print("我是普通方法") 15 16#单下划线方法 17def _otherMethod(): 18 print("我是单下划线方法") 19 20#普通类 21class PClass(object): 22 23 def __init__(self): 24 print("普通类的初始化") 25 26#单下划线类 27class _WClass(object): 28 29 def __init__(self): 30 print("单下划线类的初始化")
将上述修改过的Test.py文件导入,进行测试。
1>>> from Test import * 2>>> value 3'Java' 4>>> _otherValue 5'Python' 6>>> method() 7Traceback (most recent call last): 8 File "<pyshell#4>", line 1, in <module> 9 method() 10NameError: name 'method' is not defined 11>>> _otherMethod() 12我是单下划线方法 13>>> p=PClass() 14Traceback (most recent call last): 15 File "<pyshell#6>", line 1, in <module> 16 p=PClass() 17NameError: name 'PClass' is not defined 18>>> w= _WClass() 19单下划线类的初始化
_ all _是一个字符串列表,不管是普通的还是单下划线的属性、方法和类,都将导出来,使用其他不在这个字符列表上的属性、方法和类,都会报未定义的错误。
不管是属性、方法和类,只要名称前面加了单下划线,都不能导入。除非是模块或包中的“_ all_”列表显式地包含了它们。
名称前的双下划线(如:__name)
我们先看看下面的程序:
1class Method(object): 2 # 构造器方法 3 def __init__(self, name): 4 # 双下划线属性 5 self.__name = name 6 # 普通方法 7 def sayhello(self): 8 print("Method say hello!") 9 # 双下划线方法 10 def __sayhi(self): 11 print("Method say hi!") 12 13# 初始化Method 14m = Method("Python") 15# 调用sayhello方法 16m.sayhello() 17# 调用sayhi方法 18m.__sayhi() 19# 输出属性__name 20print(m.__name)
上面的程序定义了一个类,这个类有三个方法,一个构造器方法,一个普通方法,一个双下划线方法,以及包括一个双下划线的属性。上面的结果输出的是什么?很多读者可能认为输出的结果如下:
1Method say hello! 2Method say hi! 3Python
那么恭喜你,上面的输出结果是错误的,实际输出的结果为:
1Method say hello! 2Traceback (most recent call last): 3 File "<encoding error>", line 18, in <module> 4AttributeError: 'Method' object has no attribute '__sayhi'
实际上,当对象调用__sayhi()方法时,将会报Method类没有这个方法属性的错误。那如何去调用以双下划线开头的方法和属性?Python这样设计的目的是什么?
首先回答第一个问题,读者看完下面的程序就知道怎么调用了。
1class Method(object): 2 3 def __init__(self, name): 4 self.__name = name 5 6 def sayhello(self): 7 print("Method say hello!") 8 9 def __sayhi(self): 10 print("Method say hi!") 11 12 13# 初始化Method 14m = Method("Python") 15# 调用sayhello方法 16m.sayhello() 17# 调用sayhi方法 18#m.__sayhi() 19m._Method__sayhi() 20# 输出属性__name 21#print(m.__name) 22print(m._Method__name)
输出结果如下:
1Method say hello! 2Method say hi! 3Python
我们从上面的程序中可以很清楚的看到,如果要调用以双下划线开头的方法和属性,只要以“类名_方法(属性)”的形式就可以实现方法或者属性的访问了。类前面是单下划线,类名后面是双下划线,然后再加上方法或者属性。但是并不建议调用,因为这是Python内部进行调用的形式。
回答完第一个问题,我们看看第二个问题,Python这样设计的目的是什么?
有很多人认为,Python以双下划线开头的方法和属性表示私有的方法和属性,实际上这样的理解不太准确,也不能说完全错误的。但是这并不是Python设计的目的和初衷,我们先看看下面一段程序和程序运行结果:
1class AMethod(object): 2 3 def __method(self): 4 print("__method in class Amethod!") 5 6 def method(self): 7 self.__method() 8 print("anthod method in class AMethod!") 9 10class BMethod(AMethod): 11 12 def __method(self): 13 print("__method in class Bmethod!") 14 15 16if __name__=="__main__": 17 18 print("调用AMethod的method方法") 19 a = AMethod() 20 a.method() 21 22 print("调用BMethod的method方法") 23 b = BMethod() 24 b.method()
上面的程序定义了两个类,一个是AMethod类,另外一个是继承了AMethod类的BMethod类。在AMethod类中,定义了两个方法,一个是以双下划线开头的__method方法,另外一个是普通方法。在BMethod类中,重写了AMethod类中的__method方法。
程序运行结果:
1调用AMethod的method方法 2__method in class Amethod! 3anthod method in class AMethod! 4调用BMethod的method方法 5__method in class Amethod! 6anthod method in class AMethod! 7
运行结果并不是我们想要的结果,b.method()并没有调用BMethod类的__method方法,而这个设计的实际目的是为了避免父类的方法被子类轻易的覆盖。
名称前后的双下划线(如:_ init _)
在Python类中,我们可以常常看到类似于“_ init _ ”的方法,这表示在Python内部调用的方法,一般不建议在程序中调用。比如,当调用len()方法时,实际上调用了 Python中内部的 _ len _ 方法,虽然不建议调用这种以双下划线开头以及结尾的方法,但是可以对这些方法进行重写。比如下面的例子:
1class Number(object): 2 3 def __init__(self, number): 4 self.number = number 5 6 def __add__(self, number): 7 # 重写方法,返回两个数的差值 8 return self.number - number 9 10 def __sub__(self, number): 11 # 重写方法,返回两个数的和 12 return self.number + number 13 14 def __str__(self): 15 # 重写方法,返回字符串 16 return str(self.number) 17 18 19num = Number(100) 20print(num) # 100 调用了__str__方法 21print(num+50) # 50 + 调用了__add__方法 22print(num-20) # 120 -调用了__sub__方法
相信看了上面所有对Python中下划线作用的讲解,完全能够理解上述四种下划线所表示的意义。最后将对上面的,进行总结。
总结
单下划线(_): 在交互解释器中,表示上一条语句执行输出的结果。另外,单下划线还可以作为特殊的临时变量,表示在后面将不会在用到这个变量。
名称前的单下划线:只能在内部使用,是API中非公开的部分,不能被 import * 和 from import *导入程序中,除非在all列表中包含了以单下划线开头的属性、方法以及类。
名称前的双下划线:以双下划线开头的属性、方法表示避免父类的属性和方法被子类轻易的覆盖,一般不建议这样定义属性和方法,除非你自己将要做什么。
名称前后的双下划线:这类方法是Python内部定义的方法,你可以重写这些方法,这样Python就可以调用这个重写的方法以及利用操作符。