简体   繁体   English

__init__中的python名称修改似乎不一致

[英]python name mangling in __init__ seems inconsistent

I'm trying to use a subclass that enhances instead of overriding the base class. 我试图使用增强的子类,而不是重写基类。 I'm using the super method to call the base class. 我正在使用super方法调用基类。 I find that I need to use the name mangling feature in __init__ (but only in init?) to make the code work. 我发现我需要在__init__使用名称修改功能(但仅在init中使用)才能使代码正常工作。 So for the heck of it I made the this print example. 因此,对于这个问题,我给出了这个打印示例。 Since I didn't use name mangling I expected it to call subclass twice when I did the init, instead it calls the base class 因为我没有使用名称修饰,所以我希望它在初始化时两次调用子类,而是调用基类

It seems that __init__ sometimes sees the base class and sometimes sees the subclass. 似乎__init__有时会看到基类,有时会看到子类。 I'm sure it's just an incomplete understanding on my part, but was do I need name mangling for the real code, when in the print example it calls the base and subclass just fine? 我确定这只是我的一个不完整的理解,但是我是否需要对真实代码进行名称修饰,而在打印示例中,它调用基类和子类就很好了吗?

the code 编码

class base:
    def __init__(self):
        self.print()

    def print(self):
        print("base")

class subclass(base):
    def __init__(self):
        super(subclass, self).__init__()
        self.print()

    def print(self):
        super(subclass, self).print()
        print("subclass")

x = base()
x.print()
print("--")
y = subclass()
y.print()

the output - why doesn't y = subclass() print subclass instead of base since I didn't use name mangling? 输出-为什么y = subclass()打印subclass而不是base subclass ,因为我没有使用名称修饰?

> ./y.py 
base
base
-- 
base
subclass
base
subclass
base  
subclass

broken code when I don't use name mangling, works when I use self.__set and __set = set (the commented code). 当我不使用名称__set = set时,代码会损坏,当我使用self.__set__set = set (注释代码)时,代码会__set = set It gets the following error when I don't use __set : 当我不使用__set时,它得到以下错误:

File "./x.py", line 5, in __init__
   self.set(arg)
TypeError: set() missing 1 required positional argument: 'arg2'

the code: 编码:

class base:
    def __init__(self, arg):
        self.set(arg)
        # self.__set(arg)

    # __set = set

    def set(self, arg):
        self.arg = arg

    def print(self):
        print("base",self.arg)

class subclass(base):
    def __init__(self, arg1, arg2):
        super(subclass, self).__init__(arg1)
        self.set(arg1, arg2)

    def set(self, arg1, arg2):
        super(subclass, self).set(arg1)
        self.arg2 = arg2

    def print(self):
        super(subclass, self).print()
        print("subclass", self.arg2, self.arg)

x = base(1)

x.print()
x.set(11)
x.print()

y = subclass(2,3)

y.print()
y.set(4,5)
y.print()

======= update ======= =======更新=======

I rewrote the code to look like this: 我重新编写了代码,如下所示:

class base:
    def __init__(self):
        print("base init")
        self.print()

    def print(self):
        print("base print")

class subclass(base):
    def __init__(self):
        print("sc init")
        super(subclass, self).__init__()
        print("sc after super")
        self.print()

    def print(self):
        print("subclass print start")
        super(subclass, self).print()
        print("subclass print")

y = subclass()
print("--")
y.print()

when I run I get this output: 当我运行时,我得到以下输出:

sc init
base init
subclass print start <<<< why is the subclass print called here
base print
subclass print
sc after super
subclass print start
base print
subclass print
--
subclass print start
base print
subclass print

why does the self.print in the base init call the subclass print when I'm initing the subclass? 为什么在初始化子类时,基初始化中的self.print调用子类print? I was expecting that to call the base print. 我期望这可以打基础打印。 it does call the base print when I call it outside of the init. 当我在init之外调用它时,它的确调用了基本打印。

Your subclass print explicitly calls the superclass one. 您的子类print显式调用超类。 So every time subclass.print is called, both "base" and "subclass" will be printed. 所以每次subclass.print被调用时, 这两个 “基地”和“子”将被打印出来。 This happens three times, because you call the print method three times: in subclass.__init__ , in base.__init__ (which is called by subclass.__init__ ), and in subclass.print (which calls the superclass version). 这会发生三次,因为您调用了print方法三次:在subclass.__init__base.__init__ (由subclass.__init__ )和subclass.print (称为超类版本)中。

In your "set" example, subclass.__init__ calls base.__init__ , which tries to call self.set with just one argument. 在您的“ set”示例中, subclass.__init__调用base.__init__ ,该尝试尝试仅使用一个参数调用self.set But since you are instantiating subclass , self.set is subclass.set , which takes two arguments. 但是由于您要实例化subclassself.setsubclass.set ,它需要两个参数。

It's unclear what you're trying to achieve with these examples. 目前尚不清楚您要通过这些示例实现什么。 Your subclass doesn't really need to call base.__init__ , because all that would do is call base.set , and you're already calling that from subclass.set . 您的子类实际上不需要调用base.__init__ ,因为只需要调用base.set ,而您已经从subclass.set调用了它。 So even if you succeeded with all your calls, it would result in some methods getting called multiple times, just like with the print example. 因此,即使您成功完成所有调用,也将导致多次调用某些方法,就像print示例一样。

My impression is that you're getting a bit carried away and trying to have every method call its superclass version. 我的印象是,您有点不知所措,并试图让每个方法都调用其超类版本。 That's not always a good idea. 这并不总是一个好主意。 If you write a subclass, and it calls a superclass method, you need to make sure that the subclass still provides an interface that's compatible with what the superclass expects. 如果编写子类并调用超类方法,则需要确保该子类仍提供与该超类期望的接口兼容的接口。 If it doesn't, you may need to not call the superclass method and instead have the subclass incorporate its functionality "inline" (although this may be more risky if other classes out in the world have made assumptions about how the base class works). 如果没有,你可能需要调用父类的方法,而是有子类包括它的功能“内联”(尽管这可能是更危险的,如果其它类列世界作出了关于如何在基类作品的假设) 。 The upshot is that you always need to think about what methods call which others; 结果是您总是需要考虑哪些方法调用了其他方法。 you can't just call every superclass method everywhere and expect that to work. 您不能只在每个地方都调用每个超类方法,并期望它能工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM