每日一python(11):python中下划线的意义

本文详细解析Python中单下划线、双下划线及特殊变量的作用与使用场景,包括变量保护、私有化及内置变量的概念,帮助读者深入理解Python的命名规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 单下划线(_)

1.1 在解释器中

单下划线(_)符号是指交互解释器中最后一次执行语句的返回结果。这种用法最初出现在CPython解释器中,其他解释器后来也都跟进了。

例如:

>>> _
Traceback (most recent call last):
  File "", line 1, in 
NameError: name '_' is not defined
>>> 42
>>> _
42
>>> 'alright!' if _ else ':('
'alright!'
>>> _
'alright!'

1.2 作为名称使用

这与上面一点稍微有些联系,此时的单下划线作为临时性的名称使用。这样,当其他人阅读你的代码时将会知道,你分配了一个特定的名称,但是并不会在后面再次用到该名称。
例如,下面的例子中,你可能对循环计数中的实际值并不感兴趣,此时就可以使用(_)。

n = 42
for _ in range(n):
    do_something()

2 变量中的下划线

2.1 单下划线开头的变量(_XXX)

以单下划线开头的变量,表明这是一个**受保护(protected)**的变量,原则上不允许直接访问,但是外部类还是可以访问到这个变量。因为这只是一个程序员之间的约定,用于警告说明这是一个受保护的变量,外部类不要去访问它。

以单下划线做前缀的变量表名了这个变量是“私有的”。在 有些 导入( import *) 的场景中,下一个使用你代码的人(或者你本人)会明白这个名称仅内部使用。Python documentation里面写道:
在这里插入图片描述
以单下划线’_'为前缀的名称,如_xxx,应该被视为API中非公开的部分(不管是函数,方法还是数据成员)。此时,应该将它们看做一种实现细节,在修改他们时无需对外部通知。

例如:

class Student(object):
    def __init__(self, name, age):
        self._name = name
        self.age = age

st = Student("Yi", 31)
print(st._name)              #   Yi
print(st.age)                #   31

正如上面所说,这确实类似一种惯例,因为它对解释器来说确实有一定的意义,如果你写了代码 from <模块/包名> import *,那么以’_'开头的名称都不会被导入,除非模块或包中的__all__列表显示地包含了它们。不过值得注意的是,如果使用 import module 这样的方式导入模块,仍然可以用 module._var这样的形式访问到这样的对象。

例如:

模块test1.py

'''模块test1.py'''
# 定义2个模块变量

num  = 10
_num = 40

模块test2.py

'''模块test2.py'''
from test1 import *

print(num)
print(_num)

打印结果:
在这里插入图片描述
从上面的结果可以看到:采用 from <模块/包名> import * 方式导入时,以’_'开头的变量不会被导入!!

但是 当以 import moule 的方式导入时,以’_'开头的变量就会被导入,如下:

模块test3.py

'''模块test3.py'''
import test1

print(test1.num)
print(test1._num)

打印结果:
在这里插入图片描述

2.2 双下划线开头的变量(__XXX)

在Python中,实例的变量名如果以双下划线( __ )开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。因为Python解释器对外把 __xxx变量改成了_classname__xxx,所以,仍然可以通过_classname__xxx来访问__xxx变量。

例如:

class Student(object):
    def __init__(self, name, score, age):
        self.__name = name
        self.__score = score
        self.age = age

st = Student("Yi", 88, 31)
print(st.age)      #  返回: 31
print(st.__name)   #  报错: AttributeError: 'Student' object has no attribute '__name'
print(st._Student__name)      # 返回: Yi

从上面的结果可以看到:这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮

但是如果外部代码一定要获取namescore怎么办?可以给Student类增加get_name()get_score()方法。如下:

class Student(object):
    def __init__(self, name, age):
        self.__name = name
        self.age = age

    def get_name(self):
        return self.__name
    
    def get_score(self):
        return self.__score

st = Student("Yi", 31)
print(st.age)      #  返回: 31
#print(st.__name)   #  报错: AttributeError: 'Student' object has no attribute '__name'
print(st._Student__name)      # 返回: Yi
print(st.get_name())          # 返回: Yi
print(st.get_score())         # 返回: 88

如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score()方法,如下:

class Student(object):
    def __init__(self, name, age, score):
        self.__name = name
        self.__score = score
        self.age = age

    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score

    def set_score(self, score):
        self.__score = score


st = Student("Yi", 31, 88)
print(st.age)      #  返回: 31
#print(st.__name)   #  报错: AttributeError: 'Student' object has no attribute '__name'
print(st._Student__name)      # 返回: Yi
print(st.get_name())          # 返回: Yi
print("修改前的学生分数:" , st.get_score())    # 返回: 88
st.set_score(95)
print("修改后的学生分数:", st.get_score())     # 返回: 95

也许,我们会有个疑问,直接通过st.score = 99就可以修改啊,这里为什么要定义一个方法大费周折呢?
这是因为在方法中,可以对参数做检查,避免传入无效的参数。例如:

class Student(object):
    def __init__(self, name, age, score):
        self.__name = name
        self.__score = score
        self.age = age

    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score

    def set_score(self, score):
        if 0 <= score <= 100:
            self.__score = score
        else:
            raise ValueError('bad score')


st = Student("Yi", 31, 88)
print(st.age)           #  返回: 31
#print(st.__name)       #  报错: AttributeError: 'Student' object has no attribute '__name'
print(st._Student__name)      # 返回: Yi
print(st.get_name())    # 返回: Yi
print("修改前的学生分数:" , st.get_score())    # 返回: 88
st.set_score(95)
print("修改后的学生分数:", st.get_score())     # 返回: 95
st.set_score(120)       # 报错:raise ValueError('bad score')

2.3 双下划线开头和结尾的变量( __ XXX__)

在Python中,类似__xxx__的变量名,也就是以双下划线开头,并且以双下划线结尾的变量,是 特殊变量, 也可以称之为内置变量,。
特殊变量是可以直接访问的,不是private变量,、如__init____import__或是__file__。所以,最好不要自己定义这类变量。

3 方法中开头和结尾的双下划线

这些是Python的特殊方法名,这仅仅是一种惯例,一种确保Python系统中的名称不会跟用户自定义的名称发生冲突的方式。
通常你可以覆写这些方法,在Python调用它们时,产生你想得到的行为。例如,当写一个类的时候经常会覆写__init__方法。

4 结论

1、_xxx 不能用于from module import * 以单下划线开头的表示的是 受保护的(protected) 类型的变量。保护类型变量只能允许其本身与其子类进行访问。

2、__xxx 双下划线开头的变量表示的是私有类型(private)的变量。只能是允许这个类本身进行访问了,连子类也不可以

3、__xxx___ 定义的是特列方法。像__init__之类的

### IntelliJ IDEA 中通义 AI 功能介绍 IntelliJ IDEA 提供了一系列强大的工具来增强开发体验,其中包括与通义 AI 相关的功能。这些功能可以帮助开发者更高效地编写代并提高生产力。 #### 安装通义插件 为了使用通义的相关特性,在 IntelliJ IDEA 中需要先安装对应的插件: 1. 打开 **Settings/Preferences** 对话框 (Ctrl+Alt+S 或 Cmd+, on macOS)。 2. 导航到 `Plugins` 页面[^1]。 3. 在 Marketplace 中搜索 "通义" 并点击安装按钮。 4. 完成安装后重启 IDE 使更改生效。 #### 配置通义服务 成功安装插件之后,还需要配置通义的服务连接信息以便正常使用其提供的各项能力: - 进入设置中的 `Tools | Qwen Coding Assistant` 菜单项[^2]。 - 填写 API Key 和其他必要的认证参数。 - 测试连接以确认配置无误。 #### 使用通义辅助编程 一旦完成上述准备工作,就可以利用通义来进行智能编支持了。具体操作如下所示: ##### 自动补全代片段 当输入部分语句时,IDE 将自动提示可能的后续逻辑,并允许一键插入完整的实现方案[^3]。 ```java // 输入 while 循环条件前半部分... while (!list.isEmpty()) { // 激活建议列表选择合适的循环体内容 } ``` ##### 解释现有代含义 选中某段复杂的表达式或函数调用,右键菜单里会有选项可以请求通义解析这段代的作用以及优化意见。 ##### 生产测试案例 对于已有的业务逻辑模块,借助于通义能够快速生成单元测试框架及初始断言集,减少手动构建的成本。 ```python def test_addition(): result = add(2, 3) assert result == 5, f"Expected 5 but got {result}" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值