Python 中的_和__用约定
在 Python 中,单下划线 `_` 和双下划线 `__` 作为前缀有不同的含义和约定,以下是它们的核心区别和用法:
---
### **1. 单下划线前缀 `_xxx`**
#### **含义**
- **约定私有性**:单下划线前缀是开发者之间的约定,表示「这个变量/方法仅供内部使用」,**不会触发 Python 解释器的任何特殊行为**。
- **模块级的隐藏**:在模块中,`from module import *` 时,`_xxx` 不会被导入。
#### **示例**
```python
class MyClass:
def __init__(self):
self._internal_data = 42 # 约定为内部变量
def _internal_method(self):
return "This is internal"
```
#### **特点**
- **可以访问**:外部依然可以直接访问 `obj._internal_data` 或调用 `obj._internal_method()`。
- **IDE 提示**:部分 IDE 会提示「受保护的访问」。
---
### **2. 双下划线前缀 `__xxx`**
#### **含义**
- **名称修饰(Name Mangling)**:Python 解释器会自动将 `__xxx` 重命名为 `_类名__xxx`,目的是**避免子类与父类的属性名冲突**。
- **强制私有性**:实际效果是让属性更难被意外覆盖,但依然可以通过修饰后的名称访问。
#### **示例**
```python
class Parent:
def __init__(self):
self.__secret = "Parent's secret" # 会被重命名为 _Parent__secret
class Child(Parent):
def __init__(self):
super().__init__()
self.__secret = "Child's secret" # 会被重命名为 _Child__secret
parent = Parent()
child = Child()
print(parent.__dict__) # 输出: {'_Parent__secret': "Parent's secret"}
print(child.__dict__) # 输出: {'_Parent__secret': "Parent's secret", '_Child__secret': "Child's secret"}
```
#### **特点**
- **无法直接访问**:尝试 `obj.__secret` 会报 `AttributeError`。
- **强制隔离**:子类和父类的 `__secret` 会被重命名为不同的名称,避免冲突。
- **依然可访问**:通过 `obj._Parent__secret` 可以强行访问(但不推荐)。
---
### **核心区别**
| **特性** | `_xxx` (单下划线) | `__xxx` (双下划线) |
|------------------------|----------------------------------|---------------------------------|
| **解释器行为** | 无特殊处理 | 名称修饰(Name Mangling) |
| **实际用途** | 约定为内部使用 | 强制避免子类命名冲突 |
| **外部直接访问** | 可以(不推荐) | 不可直接访问(需用修饰后的名称) |
| **继承中的表现** | 子类可直接覆盖 | 子类无法覆盖父类的同名属性 |
---
### **使用场景建议**
1. **单下划线 `_xxx`**:
- 当你想提示其他开发者「这个属性/方法不要随意修改」时。
- 模块中定义不希望被 `from module import *` 导入的变量。
2. **双下划线 `__xxx`**:
- 当设计类继承结构时,**防止子类意外覆盖父类属性**。
- 强制实现「伪私有性」(Python 没有真正的私有变量)。
---
### **反模式警告**
```python
# 反例:强行访问双下划线变量
obj = MyClass()
print(obj._MyClass__secret) # 可以访问,但破坏封装性
```
---
### **总结**
- **单下划线**:约定优于强制,是 Python 社区的「君子协定」。
- **双下划线**:解释器级保护,用于避免继承时的命名冲突。
- 遵循这些约定可以让代码更清晰、更健壮。
更多推荐

所有评论(0)