对名称修改目的的总结是不是正确?
Posted
技术标签:
【中文标题】对名称修改目的的总结是不是正确?【英文标题】:Is this summary of the purpose of name mangling correct?对名称修改目的的总结是否正确? 【发布时间】:2021-05-30 08:39:36 【问题描述】:来自文档:
由于类私有成员有一个有效的用例(即避免名称与子类定义的名称发生名称冲突),因此对这种称为名称修饰的机制的支持有限。 __spam 形式的任何标识符(至少两个前导下划线,最多一个尾随下划线)在文本上被替换为 _classname__spam,其中类名是当前类名,前导下划线被去除。只要它出现在类的定义中,就可以在不考虑标识符的语法位置的情况下完成这种修饰。
我的解释:
修改父类方法的名称parent.__m(a, b)
以允许子类使用额外参数child.m(a, b, c)
重载它。这样,当您调用 child.m(1, 2, 3)
时,额外的参数不会被传递给父类并使其混淆。
如果您打算保留相同的方法签名但更改一些内部功能,则不需要修改。您仍然可以使用 super()
访问旧功能。
总而言之,如果您希望将来能够重载类方法,请修改它。否则就没有必要了。
问题:
我的总结正确吗?文档写得不好。大量重复的句子和中间(旁白)使我无法确定自己是否理解正确。
编辑:我刚刚玩了一些代码:
class Parent( object ):
def __init__(self, a, b):
self.a = a
self.b = b
def method( self ):
return 1
class Child(Parent):
def __init__(self, a, b, c ):
super().__init__(a, b)
def method(self, c):
field = [c]
return field
a, b, c = 0, 1, 2
c = Child(a, b, c)
print(c)
这很好用。我遇到的唯一问题是如果我这样做:
class Parent( object ):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = self.method()
def method( self ):
return 1
class Child(Parent):
def __init__(self, a, b, c ):
super().__init__(a, b)
self.c = self.method(c)
def method(self, c):
field = [c]
return field
a, b, c = 0, 1, 2
c = Child(a, b, c)
返回
TypeError: method() missing 1 required positional argument: 'c'
此答案中对此进行了讨论:Python, Overriding an inherited class method
所以说到底我还是不明白目的是什么。
【问题讨论】:
您不需要重载/覆盖,因为方法是按顺序定义的。子类中的定义将是唯一有效的定义。如果签名不同,它仍然可以工作,尽管 linter 可能不喜欢它 是的,我刚刚添加了一个我发现的编辑。玩了一些代码后,我明白了你在说什么。 【参考方案1】:子类不需要名称修改来覆盖具有更多参数的方法。其目的是防止重写方法,特别是重写为类提供某种内部目的且其行为不应被子类更改的“私有”方法。
这个想法是,如果一个子类声明一个“相同”名称的方法,它将被修改为不同的方法以避免覆盖超类的方法。与 Java 进行比较和对比,Java 中的 private
方法不能被覆盖,甚至不能在子类中调用。
class A:
def foo(self):
self.bar()
self.__baz()
def bar(self):
print('A.bar')
def __baz(self):
print('A.__baz')
class B(A):
def bar(self):
print('B.bar')
def __baz(self):
print('B.__baz')
B().foo()
输出:
B.bar
A.__baz
请注意,这是关于覆盖,而不是重载。 Python没有方法重载,方法调用中参数的数量或类型不用于确定调用哪个方法;仅使用方法名称。
【讨论】:
好的,我想我明白了......在你的任意例子中,A.__baz
有一些你不想失去的功能,如果在 B 中使用相同的名称?所以 mangling 保护了那个方法。
@rocksNwaves 完全正确。
如果在其他父类方法中使用A.__baz
,例如def booboo(): return self.__baz()
,那么现实世界的用例将是。在这种情况下,A.booboo()
依赖于子类没有窃取baz
名称的事实???抱歉,foo, bar baz 很难与现实世界的用例联系起来。对我来说太抽象了,无法全部记住。
是的,在这个例子中foo
就是那个方法。例如,考虑一个使用“私有”堆的优先级队列类,使用“私有”__sift_up
和 __sift_down
方法在从堆中添加和删除时提供帮助。如果一个子类改变了这些方法的作用,那么这个类就会中断。
干杯。因此,要维护给定名称的父类功能。你已经消除了一个很大的误解。祝你有美好的一天!以上是关于对名称修改目的的总结是不是正确?的主要内容,如果未能解决你的问题,请参考以下文章