在 python 中,以两个下划线开头(如 __method)的方法或属性,并不完全是“私有方法”(private method)——因为 python 并没有像 java 或 c++ 那样严格的访问控制机制。但这种命名方式会触发一种叫做 名称改写(name mangling)的机制,从而在一定程度上实现“私有性”。
1. 名称改写(name mangling)
当你在一个类中定义一个以双下划线开头、且不以双下划线结尾的方法或属性时,python 解释器会自动将其名称改写为:
_classname__original_name
例如:
class myclass:
def __init__(self):
self.__private_var = 42
def __private_method(self):
return "this is private"
obj = myclass()
# obj.__private_method() # attributeerror!
print(obj._myclass__private_method()) # 可以访问,但不推荐
虽然你仍然可以通过 _classname__name 的方式访问到这个“私有”成员,但这是一种约定+语言机制,目的是防止子类意外覆盖父类的内部方法,也提示开发者“这是内部使用的,不要直接调用”。
2. 与单下划线的区别
- 单下划线开头(如
_method):只是约定表示“内部使用”,不会触发名称改写,外部仍可访问。 - 双下划线开头(如
__method):触发名称改写,提供更强的封装暗示。
3. 特殊方法(魔术方法)例外
注意:如果方法名前后都有两个下划线(如 __init__, __str__),这是 python 的特殊方法(也叫魔术方法),不会被名称改写,也不表示私有,而是用于实现特定语言特性。
1. 类的特殊方法(魔术方法)
以双下划线开头和结尾的方法,被称为特殊方法或者魔术方法(magic methods)。这些方法由 python 解释器自动调用,我们可以通过重写它们来实现特定的类行为。
示例:
class myclass:
def __init__(self, value): # 实例初始化方法
self.value = value
def __str__(self): # 定义实例的字符串表示
return f"myclass(value={self.value})"
def __add__(self, other): # 定义加法操作
return myclass(self.value + other.value)
def __len__(self): # 定义长度
return len(str(self.value))
常用的魔术方法:
__init__:对象初始化__str__和__repr__:字符串表示__len__:长度__add__、__sub__、__mul__:算术运算符__eq__、__lt__、__gt__:比较运算符__iter__和__next__:迭代器协议__getitem__和__setitem__:索引操作
4.与单下划线的区别
- 单下划线(_method):这是一种约定,表示方法是受保护的(protected),不应该在类外部直接使用。不过 python 并不会强制限制这种访问。
- 双下划线(__method):会通过名称修饰机制,让方法更难以被外部访问,主要用于避免子类命名冲突。
示例对比:
class parent:
def _protected(self): # 单下划线
return "受保护的方法"
def __private(self): # 双下划线
return "私有的方法"
class child(parent):
pass
c = child()
print(c._protected()) # 可以正常调用
print(c._parent__private()) # 可以访问,但需要使用修饰后的名称
print(c.__private()) # 报错:attributeerror
4. 注意事项
- 避免过度使用双下划线:除非确实需要防止子类覆盖方法,否则建议使用单下划线来表示约定上的私有性。
- 特殊方法和私有方法:不要混淆特殊方法(如
__str__)和私有方法(如__private)。特殊方法是 python 语言的一部分,而私有方法是类设计的一种选择。
总结
- python 没有真正的“私有方法”。
__method会被名称改写,起到模拟私有的作用。- 仍可通过
_classname__method访问,但应避免这样做。 - 这是一种约定 + 语言机制,用于封装和避免命名冲突。
到此这篇关于python 双下划线开头的具体使用的文章就介绍到这了,更多相关python 双下划线开头内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论