私有变量
Python 中不存在只能从对象内部访问的“私有”实例变量。但是,大多数 Python 代码都遵循一种约定:带有下划线前缀的名称(例如 _spam)应被视为 API 的非公共部分(无论是函数、方法还是数据成员)。应将其视为实施细节,将来如有变更,恕不另行通知。
由于类私有成员有一个有效的使用场景(避免名称与子类定义的名称发生冲突),因此 Python 对这种名称改写(name mangling)的机制有简单的支持。格式为 __spam 的任何标识符(至少两个前导下划线,后面最多一个下划线)替换为 _classname__spam,其中 classname 是当前类名(去除前导下划线)。只要标识符出现在类的定义中,就不必考虑标识符的语法位置。
名称改写有助于让子类重写方法,而不破坏类内方法调用。例如:
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
__update = update # 原 update() 方法的私有拷贝
class MappingSubclass(Mapping):
def update(self, keys, values):
# 为 update() 提供新签名
# 但是并不破坏 __init__()
for item in zip(keys, values):
self.items_list.append(item)
复制
即使 MappingSubclass 引入了一个 __update 标识符,上面的示例也会起作用,因为它在 Mapping 类中被替换为 _Mapping__update,在 MappingSubclass 类中被替换为 _MappingSubclass__update。
请注意,更改规则的设计主要是为了避免意外;仍然可以访问或修改被视为私有的变量。甚至在特殊情况下很有用,例如在调试器中。
注意,传递给 exec() 或 eval() 的代码不认为调用类的类名称是当前类;这与 global 语句的效果类似。同样的限制也适用于 getattr()、setattr() 和 delattr(),以及直接引用 __dict__。
杂项
有时,使用类似于 Pascal 的 “record” 或 C 的 “struct” 数据类型,将几个命名的数据项捆绑在一起,是很有用的。空类定义就可以很好地做到这点:
class Employee:
pass
fly = Employee() # 创建空 employee
# 填充字段
fly.name = '张飞'
fly.dept = '督察队'
fly.salary = 100000
复制
一段需要特定抽象数据类型的 Python 代码通常可以传递一个类来模拟该数据类型的方法。例如,如果有一个函数格式化文件对象中的某些数据,则可以使用 read() 和 readline() 方法定义一个类,这些方法从字符串缓冲区获取数据,并将其作为参数传递。
实例方法对象也有属性:m.__self__ 是方法 m() 的实例对象,m.__func__ 是与方法对应的函数对象。
官方文档:
https://docs.python.org/3.9/tutorial/classes.html