57 lines
2.3 KiB
Markdown
57 lines
2.3 KiB
Markdown
---
|
||
title: 私有变量
|
||
date: 2020-10-03 15:32:55
|
||
tags: [Python]
|
||
categories: [Python]
|
||
author: Anges黎梦
|
||
---
|
||
|
||
### 私有变量
|
||
|
||
那种仅限从一个对象内部访问的“私有”实例变量在 Python 中并不存在。
|
||
|
||
但是,大多数 Python 代码都遵循这样一个约定:带有一个下划线的名称 (例如 _spam) 应该被当作是 API 的非公有部分 (无论它是函数、方法或是数据成员)。
|
||
|
||
这应当被视为一个实现细节,可能不经通知即加以改变。
|
||
|
||
由于存在对于类私有成员的有效使用场景(例如避免名称与子类所定义的名称相冲突),因此存在对此种机制的有限支持,称为 名称改写。
|
||
|
||
任何形式为 __spam 的标识符(至少带有两个前缀下划线,至多一个后缀下划线)的文本将被替换为 _classname__spam,其中 classname 为去除了前缀下划线的当前类名称。
|
||
|
||
这种改写不考虑标识符的句法位置,只要它出现在类定义内部就会进行。
|
||
|
||
名称改写有助于让子类重载方法而不破坏类内方法调用。例如:
|
||
|
||
```python
|
||
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 # private copy of original update() method
|
||
|
||
class MappingSubclass(Mapping):
|
||
|
||
def update(self, keys, values):
|
||
# provides new signature for update()
|
||
# but does not break __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__ 的直接引用。
|