Python中的名称修改
在名称修改过程中,任何带有两个前导下划线和一个尾随下划线的标识符在文本上都替换为_classname__identifier
,其中 classname 是当前类的名称。这意味着 __geek 形式的任何标识符(至少两个前导下划线或最多一个尾随下划线)都将替换为 _classname__geek,其中 classname 是去掉前导下划线的当前类名。
例子:
# Python program to demonstrate
# name mangling
class Student:
def __init__(self, name):
self.__name = name
def displayName(self):
print(self.__name)
s1 = Student("Santhosh")
s1.displayName()
# Raises an error
print(s1.__name)
输出
Santhosh
Traceback (most recent call last):
File "/home/be691046ea08cd2db075d27186ea0493.py", line 14, in
print(s1.__name)
AttributeError: 'Student' object has no attribute '__name'
在上面的例子中,类变量__name
在类外是不可访问的。它只能在类中访问。类变量的任何修改只能在类内部进行。
名称修改过程
在dir()
方法的帮助下,我们可以看到对类变量进行的名称修改过程。名称修改过程由解释器完成。 dir()
方法通过传递类对象来使用,它将返回属于该对象的所有有效属性。
# Python program to demonstrate
# name mangling
class Student:
def __init__(self, name):
self.__name = name
s1 = Student("Santhosh")
print(dir(s1))
输出
[‘_Student__name’, ‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’]
上面的输出显示了dir()
方法返回所有有效属性以及对类变量 __name 进行的名称修改过程。名称从 __name 更改为 _Student__name。
访问名称损坏的变量
名称修改过程有助于从类外部访问类变量。可以通过向其添加 _classname 来访问类变量。 mangling 这个名字最接近私有而不是完全私有。
# Python program to demonstrate
# name mangling
class Student:
def __init__(self, name):
self.__name = name
s1 = Student("Santhosh")
print(s1._Student__name)
输出
Santhosh
上面的类变量是通过添加 _classname 来访问的。类变量是从名为 _Student__name 的类外部访问的。
名称修改与方法覆盖
由于名称修改,对类私有成员的有效用例的支持有限,基本上是为了避免名称与子类定义的名称发生名称冲突。 __geek 形式的任何标识符(至少两个前导下划线或最多一个尾随下划线)都将替换为 _classname__geek,其中 classname 是当前类名,前导下划线被去除。只要它出现在类的定义中,这种修饰就完成了。这有助于让子类覆盖方法而不破坏类内方法调用。
让我们看一下这个例子,并尝试找出这个下划线是如何工作的:
例子:
# Python code to illustrate how mangling works
# With method overriding
class Map:
def __init__(self):
self.__geek()
def geek(self):
print("In parent class")
# private copy of original geek() method
__geek = geek
class MapSubclass(Map):
# provides new signature for geek() but
# does not break __init__()
def geek(self):
print("In Child class")
# Driver's code
obj = MapSubclass()
obj.geek()
输出:
In parent class
In Child class