python中单下划线与双下划线的区别及说明

 更新时间:2023年09月19日 10:17:05   作者:格子衫双肩包  
这篇文章主要介绍了python中单下划线与双下划线的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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中非公开的部分。

如果用fromimport * 和 fromimport * 时,这些属性、方法、类将不被导入。

# 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
 

从上面的结果可以看出,不管是属性、方法和类,只要名称前面加了单下划线,都不能导出。

如果对程序进行修改,将在开头加入__all__,结果会是如何?

# Test.py 文件
#将普通属性、单下划线的属性、方法、和类加入__all__列表
__all__=["value","_otherValue","_otherMethod","_WClass"]
#普通属性
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
'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!
Method say hi!
Python

那么恭喜你,上面的输出结果是错误的,实际输出的结果为:

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中非公开的部分,不能被import * 和 fromimport *导入程序中,除非在all列表中包含了以单下划线开头的属性、方法以及类。

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

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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Python列表的索引与切片

    Python列表的索引与切片

    这篇文章主要介绍了Python列表的索引与切片,索引用来对单个成员(元素)进行访问,切片则是对一定范围内的成员(元素)进行访问。下文相关自来需要的小伙伴可以参考一下
    2022-04-04
  • YOLOv5车牌识别实战教程(一)引言与准备工作

    YOLOv5车牌识别实战教程(一)引言与准备工作

    这篇文章主要介绍了YOLOv5车牌识别实战教程(一)引言与准备工作,在这个教程中,我们将一步步教你如何使用YOLOv5进行车牌识别,帮助你快速掌握YOLOv5车牌识别技能,需要的朋友可以参考下
    2023-04-04
  • 一文详解如何使用Python自动调整Excel行高和列宽

    一文详解如何使用Python自动调整Excel行高和列宽

    在 Excel 数据处理和报告编制过程中,确保单元格内容完整显示是常见需求,本文将介绍如何使用 Free Spire.XLS for Python 来实现自动调整 Excel 行高和列宽,有需要的小伙伴可以了解下
    2025-10-10
  • Python下载Pandas包的步骤

    Python下载Pandas包的步骤

    这篇文章主要介绍了Python下载Pandas包的步骤,在python中安装pandas库,我采取的方法是用PIP的方法在Python目标位置进行安装,本文给大家介绍的非常详细,需要的朋友可以参考下
    2025-03-03
  • Python中的错误处理与调试技巧分享

    Python中的错误处理与调试技巧分享

    在软件开发过程中,错误是不可避免的,无论是在开发初期还是在项目后期,程序都可能会遇到各种各样的错误,本文将深入探讨 Python 中的错误处理机制、常见错误类型及其处理方法,并介绍一些实用的调试技巧,以提高开发效率和代码质量,需要的朋友可以参考下
    2025-01-01
  • django-simple-captcha多种验证码的实现方法

    django-simple-captcha多种验证码的实现方法

    本文介绍了如何在Django项目中配置和使用不同类型的验证码,包括数字验证码、字母验证码和算术验证码,每种验证码结合实例代码给大家介绍得非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • pandas中DataFrame修改index、columns名的方法示例

    pandas中DataFrame修改index、columns名的方法示例

    这篇文章主要介绍了pandas中DataFrame修改index、columns名的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • 使用Python的SymPy库解决数学运算问题的方法

    使用Python的SymPy库解决数学运算问题的方法

    这篇文章主要介绍了使用Python的SymPy库解决数学运算问题的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • pytorch绘制曲线的方法

    pytorch绘制曲线的方法

    这篇文章主要为大家详细介绍了pytorch绘制曲线的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • Python中str.format()方法的具体使用

    Python中str.format()方法的具体使用

    本文主要介绍了Python中str.format()方法的具体使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09

最新评论