ITPub博客

首页 > 应用开发 > Python > 【Python】单下划线与双下划线的区别

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

原创 Python 作者:lhrbest 时间:2019-01-24 11:09:55 0 删除 编辑


Python 用下划线作为前缀和后缀指定特殊变量和定义方法,主要有如下四种形式:

单下划线( _

名称前的单下划线(如: _name

名称前的双下划线(如: __name

名称前后的双下划线(如 :__init__

(一) 单下划线( _

只有单 划线的情况,主要有两种使用场景:

1 、在交互式解释器中,单下划线“ _ ”代表的是上一条执行语句的结果。如果单下划线前面没有语句执行, 那么 交互式解释器将会报单下划线没有定义的错误。也可以对单下划线进行赋值操作,这时单下划线代表赋值的结果。但是一般不建议对单下划线进行赋值操作,因为单下划线内建标识符。

>>> _

Traceback (most recent call last):

  File "<pyshell#0>", line 1, in <module>

    _

NameError: name '_' is not defined

>>> "python"

'python'

>>> _

'python'

>>> _="Java"

>>> _

'Java'

>>>

2 、单下划线“ _ ”还可以作为特殊的临时变量。如果一个变量在后面不会再用到,并且不想给这个变量定义名称, 那么 这时就可以用单下划线作为临时性的变量。 例如, for 循环语句遍历的结果元素并不感兴趣,此时就可以用单下划线表示。

# _ 这个变量在后面不会用到

for _ in range(5):

    print("Python")

(二) 名称前的单下划线(如: _name

当在属性和方法前面加上单下划线 _ ”,用于指定属性和方法是“私有”的。但是 Python 不像 Java 一样具有私有属性、方法、类,在属性和方法之前加单下划线,只是代表该属性、方法、类只能在内部使用,是 API 中非公开的部分。如果用 from <module> import *   from <package> import * 时,这些属性、方法、类将不被导入。

# Test.py 文件

 

# 普通属性

value="Java"

 

# 单下划线属性

_otherValue="Python"

 

# 普通方法

def  method():

    print(" 我是普通方法 ")

 

# 单下划线方法

def _otherMethod():

    print(" 我是单下划线方法 ")

 

# 普通类

class PClass(object):

 

    def __init__(self):

        print(" 普通类的初始化 ")

          

# 单下划线类

class _WClass(object):

 

    def __init__(self):

        print(" 单下划线类的初始化 ")

将上述的 Test.py 文件导入,进行测试。

>>> from Test import *

>>> value

'Java'

>>> _otherValue

Traceback (most recent call last):

  File "<pyshell#4>", line 1, in <module>

    _otherValue

NameError: name '_otherValue' is not defined

>>> method()

我是普通方法

>>> _otherMethod()

Traceback (most recent call last):

  File "<pyshell#6>", line 1, in <module>

    _otherMethod()

NameError: name '_otherMethod' is not defined

>>> p=PClass()

普通类的初始化

>>> w=_WClass()

Traceback (most recent call last):

  File "<pyshell#8>", line 1, in <module>

    w=_WClass()

NameError: name '_WClass' is not defined

从上面的结果可以看出,不管是属性、方法和类,只要 名称前面加了单下划线,都不能导出。如果对程序 Test.py 进行修改,在 文件 开头加入 __all__ 结果会是如何?

# 将普通属性、单下划线的属性、方法、和类加入 __all__ 列表

__all__=["value" "_otherValue","_otherMethod","_WClass"]

修改后继续测试:

>>> from Test import *

>>> value

'Java'

>>> _otherValue

'Python'

>>> method()

Traceback (most recent call last):

  File "<pyshell#4>", line 1, in <module>

    method()

NameError: name 'method' is not defined

>>> _otherMethod()

我是单下划线方法

>>> p=PClass()

Traceback (most recent call last):

  File "<pyshell#6>", line 1, in <module>

    p=PClass()

NameError: name 'PClass' is not defined

>>> w= _WClass()

单下划线类的初始化

__all__ 是一个字符串列表,不管是普通的还是单下划线的属性、方法和类,都将导出来,使用其他不在这个字符列表上的属性、方法和类,都会报未定义的错误。不管是属性、方法和类,只要名称前面加了单下划线,都不能导入。除非是模块或包中的“ __all__ ”列表显式地包含了它们。

(三) 名称前的双下划线(如: __name

先看看下面的程序:

class Method(object):

# 构造器方法

    def __init__(self, name):

        # 双下划线属性

        self.__name = name

# 普通方法

    def sayhello(self):

        print("Method say hello!")

# 双下划线方法

    def __sayhi(self):

        print("Method say hi!")

 

# 初始化 Method

m = Method("Python")

# 调用 sayhello 方法

m.sayhello()

# 调用 sayhi 方法

m.__sayhi()

# 输出属性 __name

print(m.__name)

上面的程序定义了一个类,这个类有三个方法,一个构造器方法,一个普通方法,一个双下划线方法,以及包括一个双下划线的属性。上面 输出结果

Method say hello!

Traceback (most recent call last):

  File "<encoding error>", line 18, in <module>

AttributeError: 'Method' object has no attribute '__sayhi'

实际上,当对象调用 __sayhi() 方法时,将会报 Method 类没有这个方法属性的错误。那如何去调用以双下划线开头的方法和属性? Python 这样设计的目的是什么?

首先回答第一个问题,读者看完下面的程序就知道怎么调用了。

class Method(object):

 

    def __init__(self, name):

        self.__name = name

 

    def sayhello(self):

        print("Method say hello!")

 

    def __sayhi(self):

        print("Method say hi!")

 

 

# 初始化 Method

m = Method("Python")

# 调用 sayhello 方法

m.sayhello()

# 调用 sayhi 方法

#m.__sayhi()

m._Method__sayhi()

# 输出属性 __name

#print(m.__name)

print(m._Method__name)

输出结果如下:

Method say hello!

Method say hi!

Python

从上面的程序中可以很清楚的看到,如果要调用以双下划线开头的方法和属性,只要以 _ 类名 __ 方法(属性)”的形式就可以实现方法或者属性的访问了。类前面是单下划线,类名后面是双下划线,然后再加上方法或者属性。但是并不建议调用,因为这是 Python 内部进行调用的形式。

回答完第一个问题,我们看看第二个问题, Python 这样设计的目的是什么?

有很多人认为, Python 以双下划线开头的方法和属性表示私有的方法和属性,实际上这样的理解不太准确,也不能说完全错误的。但是这并不是 Python 设计的目的和初衷,我们先看看下面一段程序和程序运行结果 :

class AMethod(object):

 

    def __method(self):

        print("__method in class Amethod!")

 

    def method(self):

        self.__method()

        print("anthod method in class AMethod!")

 

class BMethod(AMethod):

 

    def __method(self):

        print("__method in class Bmethod!")

 

 

if __name__=="__main__":

 

    print(" 调用 AMethod method 方法 ")

    a = AMethod()

    a.method()

 

    print(" 调用 BMethod method 方法 ")

    b = BMethod()

    b.method()

上面的程序定义了两个类,一个是 AMethod 类,另外一个是继承了 AMethod 类的 BMethod 类。在 AMethod 类中,定义了两个方法,一个是以双下划线开头的 __method 方法,另外一个是普通方法。在 BMethod 类中,重写了 AMethod 类中的 __method 方法。

程序运行结果:

调用 AMethod method 方法

__method in class Amethod!

anthod method in class AMethod!

调用 BMethod method 方法

__method in class Amethod!

anthod method in class AMethod!

运行结果并不是我们想要的结果, b.method() 并没有调用 BMethod 类的 __method 方法,而这个设计的实际目的是为了避免父类的方法被子类轻易的覆盖。

(四) 名称前后的双下划线(如 __init__

Python 类中,可以常常看到类似于“ __init__ ”的方法,这表示在 Python 内部调用的方法,一般不建议在程序中调用。比如,当调用 len() 方法时,实际上调用了 Python 中内部的 __len__ 方法,虽然不建议调用这种以双下划线开头以及结尾的方法,但是可以对这些方法进行重写。比如下面的例子:

class Number(object):

 

    def __init__(self, number):

        self.number = number

 

    def __add__(self, number):

        # 重写方法,返回两个数的差值

        return self.number - number

 

    def __sub__(self, number):

        # 重写方法,返回两个数的和

        return self.number + number

 

    def __str__(self):

        # 重写方法,返回字符串

        return str(self.number)

 

num = Number(100)

print(num) # 100 调用了 __str__ 方法

print(num+50) # 50 + 调用了 __add__ 方法

print(num-20) # 120 - 调用了 __sub__ 方法

相信看了上面所有对 Python 中下划线作用的讲解,完全能够理解上述四种下划线所表示的意义。最后将对上面的,进行总结。

(五) 总结

单下划线( _ 在交互解释器中,表示上一条语句执行输出的结果。另外,单下划线还可以作为特殊的临时变量,表示在后面将不会在用到这个变量。

名称前的单下划线:只能在内部使用,是 API 中非公开的部分,不能被 <module>import   * from   <package>   import   * 导入程序中,除非在 __all__ 列表中包含了以单下划线开头的属性、方法以及类。

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

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

 




About Me

........................................................................................................................

● 本文作者:小麦苗,部分内容整理自网络,若有侵权请联系小麦苗删除

● 本文在itpub( http://blog.itpub.net/26736162 )、博客园( http://www.cnblogs.com/lhrbest )和个人weixin公众号( )上有同步更新

● 本文itpub地址: http://blog.itpub.net/26736162

● 本文博客园地址: http://www.cnblogs.com/lhrbest

● 本文pdf版、个人简介及小麦苗云盘地址: http://blog.itpub.net/26736162/viewspace-1624453/

● 数据库笔试面试题库及解答: http://blog.itpub.net/26736162/viewspace-2134706/

● DBA宝典今日头条号地址:

........................................................................................................................

● QQ群号: 230161599 (满) 、618766405

● weixin群:可加我weixin,我拉大家进群,非诚勿扰

● 联系我请加QQ好友 646634621 ,注明添加缘由

● 于 2019-01-01 06:00 ~ 2019-01-31 24:00 在魔都完成

● 最新修改时间:2019-01-01 06:00 ~ 2019-01-31 24:00

● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解

● 版权所有,欢迎分享本文,转载请保留出处

........................................................................................................................

小麦苗的微店

小麦苗出版的数据库类丛书 http://blog.itpub.net/26736162/viewspace-2142121/

小麦苗OCP、OCM、高可用网络班 http://blog.itpub.net/26736162/viewspace-2148098/

小麦苗腾讯课堂主页

........................................................................................................................

使用 weixin客户端 扫描下面的二维码来关注小麦苗的weixin公众号( )及QQ群(DBA宝典)、添加小麦苗weixin, 学习最实用的数据库技术。

........................................................................................................................

 

 



来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26736162/viewspace-2564637/,如需转载,请注明出处,否则将追究法律责任。

上一篇: Python下安装Scrapy
请登录后发表评论 登录
全部评论
【QQ:646634621】【微信:db_bao】【微信公众号:DB宝】【11g、12c OCM】【QQ群:230161599、618766405】【《数据库笔试面试宝典》作者】【OCP、OCM、高可用(RAC+DG+OGG)、MySQL培训班已开讲,只讲实用内容】

注册时间:2012-09-23

  • 博文量
    1595
  • 访问量
    9253681