Python中单下划线和双下划线分别是什么?
说到 Python 的单下划线 _ 和双下划线 __,这个面试题其实经常被人搞混,甚至有些网上教程也说得不清不楚。我自己也被坑过一次,说出来都是泪
先说单下划线 _,这货就像那种内向但关键时刻能救命的队友,在不同场景下有不同含义,必须搞清楚,否则写代码的时候出错都不知道怎么死的。
1. _ 在解释器里:最后一个表达式的值
这个最常见,在 Python 的 REPL(交互模式)里输入:
>>> 3 + 4
7
>>> _
7
这个 _ 就是前一个表达式的结果,临时存一下,很方便。你可以拿来继续操作:
>>> _ * 2
14
别小看这功能,写脚本调试的时候特好用,懒得重复输入变量名了。🐍
2. _ 作为临时变量:我懒得用它
比如你在循环里需要一个变量名,但你根本不会用它,比如:
for _ in range(5):
print("Hello")
这种写法就是告诉别人:“哥们我知道这是个循环变量,但我压根不用它,所以别在意它叫什么。”
再比如解构:
x, _, z = (1, 2, 3)
_ 这里就是个占位符,“我知道有这个位置的值,但我根本不关心它”。
注意⚠️:虽然 _ 表示“我不关心”,但它还是个变量,如果你之后用了 _,它就是上一次被赋值的内容了,所以别以为 Python 会自动忽略它。
3. _xxx:告诉你“我不想让你碰我”
这是面向对象部分的事儿了,写个类的时候,如果你看到这种写法:
classMyClass:
def__init__(self):
self._data = 42
这个 _data 意思是“这是内部变量,别乱用”,是一种约定俗成的“弱私有变量”。
注意,这只是约定!Python 不会真的拦着你用:
obj = MyClass()
print(obj._data) # 正常打印 42
这就像你家门上贴了个“私人重地,请勿打扰”,但门根本没锁……懂吧。
这其实是 Python 哲学的体现:“我们都是成年人了,我相信你不会乱搞。”
说到这,可能你已经开始吐槽了:“那还要双下划线干嘛?”
嘿嘿,双下划线 __xxx 就是另一个段子了。
4. __xxx:我要名字改写,谁也别乱动我!
当你给类成员加双下划线,Python 会搞个骚操作——“名字改写”(Name Mangling),举个栗子:
classMyClass:
def__init__(self):
self.__secret = 99
你以为不能访问?试试:
obj = MyClass()
print(obj.__secret) # 报错:AttributeError
但你偷偷看对象的属性,其实是变成了:
print(obj._MyClass__secret) # 打印 99
这个机制的初衷是为了避免子类不小心覆盖父类的私有变量。说白了,就是强制你别瞎搞。
不过讲真的,这玩意儿也不是啥安全措施。懂的人分分钟访问,甚至还能修改。真正的安全访问要靠封装和接口设计,别指望这点“障眼法”。
顺便一提,还有种神秘组合 __xxx__,比如 __init__、__str__ 这种。
5. __xxx__:Python 的保留字,不要自作主张!
这是系统保留的“魔术方法”,你定义了就会被系统自动调用,不要乱起名叫 __whatever__,你以为你酷,其实是给自己挖坑。
实战中到底怎么用?
我见过一个特别离谱的项目,所有属性都用双下划线,代码审查的时候我都看不下去了,跟他吵了一架:“你这是怕别人读懂你的代码么?”
更离谱的是,有些人习惯在函数前加 _ 当模块私有函数标记,但别人 from module import * 时还是能导入。想彻底隐藏?在模块头加个 __all__,像这样:
__all__ = ['public_function']
那 _private_function 就不会被 import * 拉进去了。
总结
_ | 2. 忽略变量(循环、解构) |
_xxx | |
__xxx | |
__xxx__ |
Python 的这个命名约定,说实话我觉得设计上不够硬核。你要是真想封装变量,弄个访问控制符不行吗?结果弄个语法糖混淆用户,看着优雅,用着就一堆坑。
不过也正因为这样,Python 的灵活性才高啊,你愿意封装就封,不封就摊开了写。这也算是它迷人的地方吧
-END-
我为大家打造了一份RPA教程,完全免费:https://www.songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领