
下划线在 Python 里用途远不止“分隔单词”。一共有六种不同写法,每种都有明确的含义和约定,弄混了要么代码出 bug,要么让同事看不懂你在写什么。
_)在交互式解释器里,_ 保存着上一次表达式的结果,临时运算很方便:
>>>10+20
30
>>>_
30 # _ 保存了上一次的结果
>>>_*2
60写数字字面量时,_ 可以当千位分隔符用,纯粹是为了可读性,运行时会被忽略:
large_number = 1_000_000
print(large_number) # 输出: 1000000
price = 9_999.99
print(price) # 输出: 9999.99循环里用 _ 表示“这个值我不用”:
# 只跑五次,不需要索引
for_inrange(5):
print("Hello, Python!")
# 解包时丢掉不需要的位置
data = (1, 2, 3, 4, 5)
first, _, third, _, fifth = data
print(first, third, fifth) # 输出: 1 3 5__xx__):魔法方法这是 Python 内置的“特殊方法”专用命名空间,__init__、__str__、__len__ 这些都属于这一类:
classMyClass:
def__init__(self, value):
self.value = value
def__str__(self):
returnf"MyClass with value: {self.value}"
def__len__(self):
returnlen(str(self.value))
obj = MyClass(42)
print(obj) # 调用 __str__
print(len(obj)) # 调用 __len__不要自己定义 __xxx__ 格式的名字——这个命名空间是 Python 保留的,随版本迭代可能会和新增的内置方法撞名。
_xx):内部使用以 _ 开头表示“这是内部实现,外部别直接用”。更实际的效果是:from module import * 不会导入这类名字。
mymodule.py:
defpublic_func():
return"This is public"
def_internal_func():
return"This is internal"导入行为的差异:
# 方式1:导入整个模块——两个都能用
importmymodule
print(mymodule.public_func()) # 正常
print(mymodule._internal_func()) # 技术上可以,但不推荐
# 方式2:通配符导入——只导入公共的
frommymoduleimport*
print(public_func()) # 正常
# print(_internal_func()) # NameError:压根没被导入进来xx_):绕过关键词冲突变量名恰好和关键词撞了,后面加 _ 就能用:
# class = "MyClass" # SyntaxError
class_ = "MyClass"
def_ = "function"
return_ = "value"
print(class_, def_, return_) # 输出: MyClass function value不过实际上能用的话,换一个完全不同的名字更好——class_ 读起来总归有点别扭。
__xx):名称修饰(Name Mangling)以 __ 开头的属性,Python 会在背后把它改名为 _ClassName__xx,目的是防止子类无意间覆盖父类的属性:
classParent:
def__init__(self):
self.public = "公共属性"
self.__private = "私有属性(经过名称修饰)"
defget_private(self):
returnself.__private
classChild(Parent):
def__init__(self):
super().__init__()
self.__private = "子类的私有属性" # 不会覆盖父类的 __private
defshow_all(self):
print(f"公共属性: {self.public}")
print(f"尝试访问父类私有属性: {self.get_private()}")
print(f"子类自己的私有属性: {self.__private}")
parent = Parent()
print(parent.public) # 输出: 公共属性
# print(parent.__private) # AttributeError
child = Child()
child.show_all()
# 公共属性: 公共属性
# 尝试访问父类私有属性: 私有属性(经过名称修饰)
# 子类自己的私有属性: 子类的私有属性Parent 里的 __private 实际存储名是 _Parent__private,Child 里的是 _Child__private,两者互不干扰。
_ClassName__xx:直接访问被修饰后的名字既然知道改名规则,就可以绕过去直接访问:
classMyClass:
def__init__(self):
self.__secret = "隐藏的秘密"
obj = MyClass()
# print(obj.__secret) # AttributeError
print(obj._MyClass__secret) # 输出: 隐藏的秘密这只适合调试或测试场景。正常业务代码里这样写,基本意味着设计出了问题。
六种写法放在一个类里看得更清楚:
classExample:
def__init__(self):
self.normal = "普通属性"
self._internal = "内部属性"
self.__private = "私有属性"
defpublic_method(self):
return"公共方法"
def_internal_method(self):
return"内部方法"
def__private_method(self):
return"私有方法"
defshow_private(self):
returnself.__private_method()
ex = Example()
print(ex.normal) # 正常
print(ex._internal) # 可以访问,但约定上别这么做
print(ex.show_private()) # 通过公共方法访问私有方法
# print(ex.__private) # AttributeError
# print(ex.__private_method) # AttributeError六种规则里,__xx__ 不要碰(Python 的地盘),_xx 和 __xx 是日常最有用的两种——前者表示“我打算内部用”,后者表示“子类别动”,理解这两个区别就够用了。
“无他,惟手熟尔”!有需要的用起来!
如果你觉得这篇文章有用,欢迎点赞、转发、收藏、留言、推荐❤!
本文分享自 Nicholas与Pypi 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!