为什么设计私有变量
大多数 Python 代码都遵循这样一个约定:带有一个下划线的名称 (例如: _spam) 应该被当作是 API 的非公有部分 (无论它是函数、方法或是数据成员)。
为了保证对于类私有成员的有效使用(例如避免名称与派生类所定义的名称相冲突),设立了名称改写(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 # 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 。改写规则的设计主要是为了避免意外冲突;访问或修改被视为私有的变量仍然是可能的。
变量的定义
xx:公有变量
_xx:单下划线,私有化属性或方法,类对象和子类可以访问,from somemodule import *禁止导入
__xx:双下划线,私有化属性或方法,无法在外部直接访问(名字改写不能访问)
__xx__:双前后下划线,系统定义名字(用户避免使用)
xx_:单下划线,用于避免与Python关键词的冲突
示例1:对于变量的访问
class student(object):
def __init__(self):
self.num = 10
self._name = "wang"
self.__grade = 30
stu = student()
print(stu.num) # 10
print(stu._name) # wang
# print(stu.__grade) # error
print(stu._student__grade) # 30
stu.__grade = 40
print(stu.__grade) # 40
print(stu._student__grade) # 30
stu._student__grade = 50
print(stu.__grade) # 40
print(stu._student__grade) # 50
尤其注意最后六行,可以看到名称改写对私有变量的影响。
可以看出,不能在外部直接访问双下划线的私有变量,而用改写后的名字即可访问,因此可知在 Python 中并没有严格意义上的私有变量。在编程的时候应该注意这一点。
示例2:从外部导入对私有变量的影响
_variable 类型的属性或方法不能通过 from module import * 语句导入,能够通过 import module 语句导入
# test.py
num = 10
_name = "wang"
__grade = 30
def get_num():
print("get_num")
def _get_name():
print("get_name")
def __get_grade():
print("get_grade")
from test import *
print(num) # 10
# print(_name) # error
# print(__grade) # error
get_num() # get_num
# _get_name() # error
# __get_grade() # error
import test
print(test.num) # 10
print(test._name) # wang
print(test.__grade) # 30
test.get_num() # get_num
test._get_name() # get_name
test.__get_grade() # get_grade
可知,利用 import ... 和 from module import ... 导入后,对于变量的引用方式也是有区别,具体可以看这篇文章。
也可以通过装饰器来调用私有变量,详细的可以看这篇文章。
参考资料:
1. Python官方文档:https://docs.python.org/zh-cn/3.7/
2. 博客:https://www.cnblogs.com/semon-code/p/8242062.html
网友评论