对名称修改目的的总结是不是正确?

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 方法在从堆中添加和删除时提供帮助。如果一个子类改变了这些方法的作用,那么这个类就会中断。 干杯。因此,要维护给定名称的父类功能。你已经消除了一个很大的误解。祝你有美好的一天!

以上是关于对名称修改目的的总结是不是正确?的主要内容,如果未能解决你的问题,请参考以下文章

VB中如何通过在文本框中输入时间日期然后直接赋值给系统时间日期,从而达到修改系统时间的目的?

软件理论基础(目的原则对象风险)

如何对会计科目进行增加、修改和删除

第二周学习总结

获取 QListWidget PyQt5 中所选项目的名称

线程同步的目的