Python中的__function和_function有不同的约定和用途。
__function
__function(双下划线前缀):
- 这被称为”name mangling”(名称修饰)
- 用于实现类的私有属性和方法
- Python会将这样的名称在内部重命名,使其更难从外部直接访问
- 主要目的是防止子类意外覆盖或重写这些方法
- 例如,
__init__是一个特殊的魔术方法(构造函数)
- 通过名称修饰,
__method会被改变为_ClassName__method
示例:
1 2 3 4 5 6 7 8 9 10 11 12
| class MyClass: def __private_method(self): print("This is a private method") def public_method(self): self.__private_method()
obj = MyClass()
|
_function
_function(单下划线前缀):
- 这是一个约定,表示”这是一个供内部使用的方法”
- 不是严格的私有方法
- 只是一个社区约定,表示”这个方法不应该被直接外部调用”
- 从语法上讲,仍然可以直接访问
- 通常用于表示”这是一个内部实现,不应该被视为公共API的一部分”
示例:
1 2 3 4 5 6 7 8 9
| class MyClass: def _internal_method(self): print("This is an internal method") def public_method(self): self._internal_method()
obj = MyClass() obj._internal_method()
|
主要区别总结:
__function:通过名称修饰实现更强的私有性,Python会改变其名称
_function:只是一个约定,表示不应直接使用,但实际上仍可访问
最佳实践:
- 尊重
_function的约定,不要直接调用带有单下划线的方法
- 如果真的需要严格的私有性,使用
__function
- 在设计类时,考虑方法的intended使用方式
深入名称修饰机制
名称修饰(Name Mangling)是Python中一种特殊的标识符重命名机制,主要用于类的属性和方法。
当你在类中定义一个以双下划线(__)开头的属性或方法时,Python会自动修改其名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class AdvancedClass: def __init__(self): self.__secret = "私有属性" self._protected = "受保护属性"
def __private_method(self): print("这是一个私有方法")
def _protected_method(self): print("这是一个受保护方法")
def access_private(self): print(self.__dict__) self.__private_method()
obj = AdvancedClass()
print(obj.__dict__) print([item for item in dir(obj) if not item.startswith('__')]) print(obj._AdvancedClass__secret) """ {'_AdvancedClass__secret': '私有属性', '_protected': '受保护属性'} ['_AdvancedClass__private_method', '_AdvancedClass__secret', '_protected', '_protected_method', 'access_private'] 私有属性 """
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Parent: def __init__(self): self.__secret = "父类秘密"
class Child(Parent): def __init__(self): super().__init__() self.__secret = "子类秘密"
def print_secrets(self): print("父类秘密:", self._Parent__secret) print("子类秘密:", self.__secret)
child = Child() child.print_secrets() """ 父类秘密: 父类秘密 子类秘密: 子类秘密 """
|
名称修饰的目的
- 防止意外重写:子类不会意外覆盖父类的私有属性
- 提供一定的封装:虽然不是绝对私有,但增加了访问的复杂性
- 命名冲突避免:在继承中防止命名冲突
实现原理
Python 的名称修饰是在编译时进行的:
- 编译器检测到以
__开头的标识符
- 自动将类名插入到标识符前
- 创建一个新的、唯一的名称
- 以双下划线开头并以双下划线结尾的方法(如
__init__)不会被修饰
查看名称修饰的字节码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import dis
class InspectMangling: def __init__(self): self.__hidden = "隐藏内容"
def show_bytecode(self): print(dis.dis(self.__init__))
obj = InspectMangling() obj.show_bytecode() """ 6 0 LOAD_CONST 1 ('隐藏内容') 2 LOAD_FAST 0 (self) 4 STORE_ATTR 0 (_InspectMangling__hidden) 6 LOAD_CONST 0 (None) 8 RETURN_VALUE None """
|
属性访问控制的高级模式
在属性的 setter 方法中调用私有方法是一种常见且实用的模式。这种方式可以帮助我们实现更复杂的验证、转换或预处理逻辑。
基本模式扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| class SmartAccessClass: def __init__(self): self.__private_attr = None
@property def private_attr(self): """ 获取属性,可以添加额外的访问控制逻辑 """ if self.__private_attr is None: return 0 return self.__private_attr
@private_attr.setter def private_attr(self, value): """ setter方法中调用私有方法进行验证和转换 """ converted_value = self.__convert_value(value) if self.__validate_value(converted_value): self.__private_attr = converted_value else: raise ValueError("值未通过验证")
def __convert_value(self, value): try: return int(value) except (TypeError, ValueError): return 0
def __validate_value(self, value): return 0 <= value <= 100
class InheritanceTest(SmartAccessClass): def __init__(self): super().__init__()
def attempt_access(self): pass
|
复杂的转换和验证逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class AdvancedAccessControl: def __init__(self): self.__sensitive_data = None
@property def sensitive_data(self): """ 安全地获取敏感数据 """ return self.__decrypt_data(self.__sensitive_data)
@sensitive_data.setter def sensitive_data(self, value): """ 设置敏感数据,包括加密和验证 """ if not self.__is_valid_input(value): raise ValueError("输入不合法") encrypted_value = self.__encrypt_data(value) self.__sensitive_data = encrypted_value
def __is_valid_input(self, value): return ( isinstance(value, str) and len(value) > 5 and any(char.isdigit() for char in value) )
def __encrypt_data(self, value): return ''.join(chr(ord(c) + 1) for c in value)
def __decrypt_data(self, encrypted_value): if encrypted_value is None: return None return ''.join(chr(ord(c) - 1) for c in encrypted_value)
obj = AdvancedAccessControl() obj.sensitive_data = "secret123" print(obj.sensitive_data)
|
带有日志和审计的访问控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| import logging from functools import wraps
class AuditedAccessClass: def __init__(self): self.__critical_value = None self.__logger = logging.getLogger(self.__class__.__name__)
def audit_access(method): """ 装饰器:记录方法调用 """
@wraps(method) def wrapper(self, *args, **kwargs): try: result = method(self, *args, **kwargs) self.__logger.info(f"成功调用 {method.__name__}") return result except Exception as e: self.__logger.error(f"调用 {method.__name__} 失败: {str(e)}") raise
return wrapper
@property @audit_access def critical_value(self): """ 带审计的属性获取 """ return self.__critical_value
@critical_value.setter @audit_access def critical_value(self, value): """ 带审计的属性设置 """ processed_value = self.__process_critical_value(value) self.__critical_value = processed_value
def __process_critical_value(self, value): """ 私有方法:处理关键值 """ if not isinstance(value, (int, float)): raise TypeError("必须是数值类型")
return round(float(value), 2)
audit_obj = AuditedAccessClass() audit_obj.critical_value = 123.456 print(audit_obj.critical_value)
|