微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

​【Python】单下划线与双下划线的区别

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

 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中非公开的部分,不能被

  • 名称前的双下划线:以双下划线开头的属性方法表示避免父类属性方法被子类轻易的覆盖,一般不建议这样定义属性方法,除非你自己将要做什么。

  • 名称前后的双下划线:这类方法是Python内部定义的方法,你可以重写这些方法,这样Python就可以调用这个重写的方法以及利用操作符。


长按下图识别二维码或微信扫描下图二维码来关注小麦苗的微信公众号:xiaomaimiaolhr,学习最实用的数据库技术。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

本文分享自微信公众号 - DB宝(lhrdba)。
如有侵权,请联系 support@oschina.cn 删除
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐