今天在修正别人代码中,碰到一个问题,大概demo是下面的
class Index:
def __init__(self):
self.__number = None
def create_number(self):
self.__number = 3
def print_number(self):
print(self.__number, '父类的')
class Inner(Index):
def __init__(self):
# 这里为什么没用super,我也不知道为什么,上个人这么写的
self.__number = None
print('这里也重写了一部分')
#
def create_number(self):
self.__number = 3
print('这里重写了某一部分')
def send_number(self):
print(self.__number, '子类的')
obj = Inner()
obj.create_number()
obj.print_number()
obj.send_number()
乍一看代码逻辑上面没有问题,但是当我程序真正执行的时候发现了直接报错了,错误显示:
AttributeError: 'Inner' object has no attribute '_Index__number'. Did you mean: '_Inner__number'?
告诉我们Inner的object没有 _Index__number这个属性,我发现我也没有定义这个属性呀,后来我修改了一下,代码改为下面这样就正常的了
class Index:
def __init__(self):
self.__number = None
def create_number(self):
self.__number = 3
def print_number(self):
print(self.__number, '父类的')
class Inner(Index):
def __init__(self):
# 这里为什么没用super,我也不知道为什么,上个人这么写的
self.__number = None
print('这里也重写了一部分')
#
def create_number(self):
super().create_number()
def send_number(self):
print(self.__number, '子类的')
obj = Inner()
obj.create_number()
obj.print_number() # 3 父类的
obj.send_number() # None 子类的
这样他就正常了,后面的方法也可以成功调用,但是我们看打印,我在子类和父类中都有一个属性叫__number这个属性,但是打印的时候调用过了create_number函数,显示的结果确不一样,父类的改为了3,子类的还是None,就小小的好奇了一下是什么原因
之前碰到的__开头我们都知道在python中是隐藏的意思,但是又记得不是真正的隐藏,所以找了一下,是我自己概念出现了错误
解释大概是这样的:
在 Python 中,以双下划线
__
开头的属性会被进行名称修饰(name mangling),变成_ClassName__attribute
的形式。这个机制是为了防止子类意外地覆盖同名的父类属性,而不是为了实现真正意义上的隐藏。虽然这种机制可以增加对属性的访问控制,但它并不是真正意义上的私有化。事实上,在 Python 中没有严格意义上的“私有”属性或方法,因为 Python 支持动态访问对象的属性和方法。
即使一个属性以双下划线开头,仍然可以通过名称修饰的方式访问到它,尽管这并不是一种推荐的做法。这也意味着,Python 中的封装和访问控制依赖于约定和规范,而不是语言层面的强制性规定。
他会被名称修饰掉,所以我们__开头的属性其实是已经被python解释器改了名字,可以确认一下是否是真的
print(vars(obj)) # {'_Inner__number': None, '_Index__number': 3}
我们可以看到对象的属性虽然我们肉眼看上去是一个,实际上已经是两个属性了,我们在子类中.__number其实是_Inner__number,而到了父类中.__number其实是_Index__number,所以会出现这样的情况,那么我们想在子类中修改父类的隐藏方法其实就可以通过下面实现
class Index:
def __init__(self):
self.__number = None
def create_number(self):
self.__number = 3
def print_number(self):
print(self.__number, '父类的')
class Inner(Index):
def __init__(self):
# 这里为什么没用super,我也不知道为什么,上个人这么写的
self.__number = None
print('这里也重写了一部分')
#
def create_number(self):
self.__number = 3
self._Index__number = 5
def send_number(self):
print(self.__number, '子类的')
obj = Inner()
obj.create_number()
print(vars(obj))
obj.print_number() # 5 父类的
obj.send_number() # 3 子类的
可以通过这样的方式直接访问到父类的隐藏属性进行修改