标签归档:superclass

__init __()是否应该调用父类的__init __()?

问题:__init __()是否应该调用父类的__init __()?

我在Objective-C中使用过这种结构:

- (void)init {
    if (self = [super init]) {
        // init class
    }
    return self;
}

Python是否还应该为调用父类的实现__init__

class NewClass(SomeOtherClass):
    def __init__(self):
        SomeOtherClass.__init__(self)
        # init class

对于__new__()和也是正确/错误__del__()吗?

编辑:有一个非常类似的问题:Python中的继承和重写__init__

I’m used that in Objective-C I’ve got this construct:

- (void)init {
    if (self = [super init]) {
        // init class
    }
    return self;
}

Should Python also call the parent class’s implementation for __init__?

class NewClass(SomeOtherClass):
    def __init__(self):
        SomeOtherClass.__init__(self)
        # init class

Is this also true/false for __new__() and __del__()?

Edit: There’s a very similar question: Inheritance and Overriding __init__ in Python


回答 0

在Python中,调用超类__init__是可选的。如果调用它,那么使用super标识符还是显式命名超类也是可选的:

object.__init__(self)

对于对象,由于super方法为空,因此不必严格要求调用super方法。相同__del__

另一方面,对于__new__,您确实应该调用super方法,并将其return用作新创建的对象-除非您明确希望返回其他内容。

In Python, calling the super-class’ __init__ is optional. If you call it, it is then also optional whether to use the super identifier, or whether to explicitly name the super class:

object.__init__(self)

In case of object, calling the super method is not strictly necessary, since the super method is empty. Same for __del__.

On the other hand, for __new__, you should indeed call the super method, and use its return as the newly-created object – unless you explicitly want to return something different.


回答 1

如果__init__除了在当前类中正在执行的操作之外,还需要从super 进行操作,则__init__,必须自己调用它,因为这不会自动发生。但是,如果您不需要super的__init__,任何东西,则无需调用它。例:

>>> class C(object):
        def __init__(self):
            self.b = 1


>>> class D(C):
        def __init__(self):
            super().__init__() # in Python 2 use super(D, self).__init__()
            self.a = 1


>>> class E(C):
        def __init__(self):
            self.a = 1


>>> d = D()
>>> d.a
1
>>> d.b  # This works because of the call to super's init
1
>>> e = E()
>>> e.a
1
>>> e.b  # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    e.b  # This is going to fail since nothing in E initializes b...
AttributeError: 'E' object has no attribute 'b'

__del__是相同的方式(但要警惕依赖于__del__完成-请考虑通过with语句代替)。

我很少使用__new__. 所有初始化方法__init__.

If you need something from super’s __init__ to be done in addition to what is being done in the current class’s __init__, you must call it yourself, since that will not happen automatically. But if you don’t need anything from super’s __init__, no need to call it. Example:

>>> class C(object):
        def __init__(self):
            self.b = 1


>>> class D(C):
        def __init__(self):
            super().__init__() # in Python 2 use super(D, self).__init__()
            self.a = 1


>>> class E(C):
        def __init__(self):
            self.a = 1


>>> d = D()
>>> d.a
1
>>> d.b  # This works because of the call to super's init
1
>>> e = E()
>>> e.a
1
>>> e.b  # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    e.b  # This is going to fail since nothing in E initializes b...
AttributeError: 'E' object has no attribute 'b'

__del__ is the same way, (but be wary of relying on __del__ for finalization – consider doing it via the with statement instead).

I rarely use __new__. I do all the initialization in __init__.


回答 2

在Anon的回答中:
“如果__init__除了在当前类中所做的事情之外,还需要从super 进行一些事情__init__,则必须自己调用它,因为这不会自动发生”

令人难以置信:他的措辞与继承原则完全相反。


不是说“ super __init__ (…)中的某事不会自动发生”,而是它会自动发生,但不会发生,因为__init__派生类的定义覆盖了基类。__init__

那么,为什么要定义一个named_class’ __init__,因为它会覆盖有人诉诸继承时的目标?

这是因为需要定义一些在基类中未完成的事情__init__,而获得该结果的唯一可能性是将其执行置于派生类的__init__函数中。
换句话说,如果在基类__init____init__没有被覆盖,除了在基类会自动完成的事情外,还需要在基类做些什么。
并非相反。


然后,问题是__init__在实例化时不再激活存在于基类中的所需指令。为了抵消这种失活,需要做一些特殊的事情:显式调用基类’ __init__,以便保留基类执行的初始化,而不是添加__init__。这就是官方文档中所说的:

实际上,派生类中的重写方法可能想扩展而不是简单地替换相同名称的基类方法。有一种直接调用基类方法的简单方法:只需调用BaseClassName.methodname(self,arguments)。
http://docs.python.org/tutorial/classes.html#inheritance

这就是全部故事:

  • 当目标是保留基类执行的初始化(即纯继承)时,不需要任何特殊操作,必须避免__init__在派生类中定义一个函数

  • 当目的是替换由基类执行的初始化时,__init__必须在派生类中定义

  • 当目标是将过程添加到由基类执行的初始化时,__init__ 必须定义一个派生类,包括对基类的显式调用__init__


在Anon的职位上,我感到惊讶的不仅是他表达了与继承理论相反的事实,而且还有5个人绕过那个被推崇而又不掉头的家伙,而且在过去的2年中,没有人反应一个线程,其有趣的主题必须相对频繁地阅读。

In Anon’s answer:
“If you need something from super’s __init__ to be done in addition to what is being done in the current class’s __init__ , you must call it yourself, since that will not happen automatically”

It’s incredible: he is wording exactly the contrary of the principle of inheritance.


It is not that “something from super’s __init__ (…) will not happen automatically” , it is that it WOULD happen automatically, but it doesn’t happen because the base-class’ __init__ is overriden by the definition of the derived-clas __init__

So then, WHY defining a derived_class’ __init__ , since it overrides what is aimed at when someone resorts to inheritance ??

It’s because one needs to define something that is NOT done in the base-class’ __init__ , and the only possibility to obtain that is to put its execution in a derived-class’ __init__ function.
In other words, one needs something in base-class’ __init__ in addition to what would be automatically done in the base-classe’ __init__ if this latter wasn’t overriden.
NOT the contrary.


Then, the problem is that the desired instructions present in the base-class’ __init__ are no more activated at the moment of instantiation. In order to offset this inactivation, something special is required: calling explicitly the base-class’ __init__ , in order to KEEP , NOT TO ADD, the initialization performed by the base-class’ __init__ . That’s exactly what is said in the official doc:

An overriding method in a derived class may in fact want to extend rather than simply replace the base class method of the same name. There is a simple way to call the base class method directly: just call BaseClassName.methodname(self, arguments).
http://docs.python.org/tutorial/classes.html#inheritance

That’s all the story:

  • when the aim is to KEEP the initialization performed by the base-class, that is pure inheritance, nothing special is needed, one must just avoid to define an __init__ function in the derived class

  • when the aim is to REPLACE the initialization performed by the base-class, __init__ must be defined in the derived-class

  • when the aim is to ADD processes to the initialization performed by the base-class, a derived-class’ __init__ must be defined , comprising an explicit call to the base-class __init__


What I feel astonishing in the post of Anon is not only that he expresses the contrary of the inheritance theory, but that there have been 5 guys passing by that upvoted without turning a hair, and moreover there have been nobody to react in 2 years in a thread whose interesting subject must be read relatively often.


回答 3

编辑:(在代码更改之后)
我们无法告诉您是否需要调用父母的__init__(或任何其他函数)。继承显然可以在没有这种调用的情况下工作。这完全取决于代码的逻辑:例如,如果所有__init__操作都在父类中完成,则可以完全跳过子类__init__

考虑以下示例:

>>> class A:
    def __init__(self, val):
        self.a = val


>>> class B(A):
    pass

>>> class C(A):
    def __init__(self, val):
        A.__init__(self, val)
        self.a += val


>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12

Edit: (after the code change)
There is no way for us to tell you whether you need or not to call your parent’s __init__ (or any other function). Inheritance obviously would work without such call. It all depends on the logic of your code: for example, if all your __init__ is done in parent class, you can just skip child-class __init__ altogether.

consider the following example:

>>> class A:
    def __init__(self, val):
        self.a = val


>>> class B(A):
    pass

>>> class C(A):
    def __init__(self, val):
        A.__init__(self, val)
        self.a += val


>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12

回答 4

没有硬性规定。类的文档应指出子类是否应调用超类方法。有时您想完全替换超类行为,而有时又要增强它-即在超类调用之前和/或之后调用您自己的代码。

更新:相同的基本逻辑适用于任何方法调用。构造函数有时需要特别考虑(因为它们经常设置确定行为的状态)和析构函数,因为它们并行构造函数(例如,在资源分配(例如数据库连接)中)。但是,对于render()小部件的方法可能也是如此。

进一步更新:什么是OPP?你是说OOP吗?否-一个子类经常需要知道一些关于超类的设计。不是内部实现细节-而是超类与其客户(使用类)所拥有的基本契约。这丝毫不违反OOP原则。这就是为什么protected在OOP中通常是一个有效的概念的原因(尽管在Python中当然不是)。

There’s no hard and fast rule. The documentation for a class should indicate whether subclasses should call the superclass method. Sometimes you want to completely replace superclass behaviour, and at other times augment it – i.e. call your own code before and/or after a superclass call.

Update: The same basic logic applies to any method call. Constructors sometimes need special consideration (as they often set up state which determines behaviour) and destructors because they parallel constructors (e.g. in the allocation of resources, e.g. database connections). But the same might apply, say, to the render() method of a widget.

Further update: What’s the OPP? Do you mean OOP? No – a subclass often needs to know something about the design of the superclass. Not the internal implementation details – but the basic contract that the superclass has with its clients (using classes). This does not violate OOP principles in any way. That’s why protected is a valid concept in OOP in general (though not, of course, in Python).


回答 5

海事组织,你应该给它打电话。如果您的超类是object,则不应这样做,但在其他情况下,我认为不调用它是一种exceptions。正如其他人已经回答的那样,如果您的类甚至不必重写__init__自身,例如在没有(其他)内部状态要初始化的情况下,这将非常方便。

IMO, you should call it. If your superclass is object, you should not, but in other cases I think it is exceptional not to call it. As already answered by others, it is very convenient if your class doesn’t even have to override __init__ itself, for example when it has no (additional) internal state to initialize.


回答 6

是的,您应该始终__init__显式调用基类,这是一种良好的编码习惯。忘记执行此操作可能会导致细微的问题或运行时错误。即使__init__不接受任何参数也是如此。这与其他语言不同,在其他语言中,编译器会为您隐式调用基类构造函数。Python不会那样做!

始终调用基类的主要原因_init__是基类通常可以创建成员变量并将其初始化为默认值。因此,如果不调用基类init,则不会执行任何代码,并且最终会得到没有成员变量的基类。

范例

class Base:
  def __init__(self):
    print('base init')

class Derived1(Base):
  def __init__(self):
    print('derived1 init')

class Derived2(Base):
  def __init__(self):
    super(Derived2, self).__init__()
    print('derived2 init')

print('Creating Derived1...')
d1 = Derived1()
print('Creating Derived2...')
d2 = Derived2()

打印..

Creating Derived1...
derived1 init
Creating Derived2...
base init
derived2 init

运行此代码

Yes, you should always call base class __init__ explicitly as a good coding practice. Forgetting to do this can cause subtle issues or run time errors. This is true even if __init__ doesn’t take any parameters. This is unlike other languages where compiler would implicitly call base class constructor for you. Python doesn’t do that!

The main reason for always calling base class _init__ is that base class may typically create member variable and initialize them to defaults. So if you don’t call base class init, none of that code would be executed and you would end up with base class that has no member variables.

Example:

class Base:
  def __init__(self):
    print('base init')

class Derived1(Base):
  def __init__(self):
    print('derived1 init')

class Derived2(Base):
  def __init__(self):
    super(Derived2, self).__init__()
    print('derived2 init')

print('Creating Derived1...')
d1 = Derived1()
print('Creating Derived2...')
d2 = Derived2()

This prints..

Creating Derived1...
derived1 init
Creating Derived2...
base init
derived2 init

Run this code.


在python中继承和覆盖__init__

问题:在python中继承和覆盖__init__

我正在阅读“深入Python”,并在有关类的章节中给出了以下示例:

class FileInfo(UserDict):
    "store file metadata"
    def __init__(self, filename=None):
        UserDict.__init__(self)
        self["name"] = filename

然后,作者说,如果要覆盖该__init__方法,则必须__init__使用正确的参数显式调用父方法。

  1. 如果该FileInfo班有一个以上的祖先班怎么办?
    • 我是否必须显式调用所有祖先类的__init__方法?
  2. 另外,我是否必须对要覆盖的其他任何方法执行此操作?

I was reading ‘Dive Into Python’ and in the chapter on classes it gives this example:

class FileInfo(UserDict):
    "store file metadata"
    def __init__(self, filename=None):
        UserDict.__init__(self)
        self["name"] = filename

The author then says that if you want to override the __init__ method, you must explicitly call the parent __init__ with the correct parameters.

  1. What if that FileInfo class had more than one ancestor class?
    • Do I have to explicitly call all of the ancestor classes’ __init__ methods?
  2. Also, do I have to do this to any other method I want to override?

回答 0

关于子类-超类调用,这本书有些过时了。在子类化内置类方面也有些过时。

如今看起来像这样:

class FileInfo(dict):
    """store file metadata"""
    def __init__(self, filename=None):
        super(FileInfo, self).__init__()
        self["name"] = filename

请注意以下几点:

  1. 我们可以直接继承内建类,如dictlisttuple,等。

  2. super函数负责跟踪此类的超类并在其中适当地调用函数。

The book is a bit dated with respect to subclass-superclass calling. It’s also a little dated with respect to subclassing built-in classes.

It looks like this nowadays:

class FileInfo(dict):
    """store file metadata"""
    def __init__(self, filename=None):
        super(FileInfo, self).__init__()
        self["name"] = filename

Note the following:

  1. We can directly subclass built-in classes, like dict, list, tuple, etc.

  2. The super function handles tracking down this class’s superclasses and calling functions in them appropriately.


回答 1

在您需要继承的每个类中,您可以运行每个需要在子类启动时进行初始化的类的循环…可以更好地理解可以复制的示例…

class Female_Grandparent:
    def __init__(self):
        self.grandma_name = 'Grandma'

class Male_Grandparent:
    def __init__(self):
        self.grandpa_name = 'Grandpa'

class Parent(Female_Grandparent, Male_Grandparent):
    def __init__(self):
        Female_Grandparent.__init__(self)
        Male_Grandparent.__init__(self)

        self.parent_name = 'Parent Class'

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
#---------------------------------------------------------------------------------------#
        for cls in Parent.__bases__: # This block grabs the classes of the child
             cls.__init__(self)      # class (which is named 'Parent' in this case), 
                                     # and iterates through them, initiating each one.
                                     # The result is that each parent, of each child,
                                     # is automatically handled upon initiation of the 
                                     # dependent class. WOOT WOOT! :D
#---------------------------------------------------------------------------------------#



g = Female_Grandparent()
print g.grandma_name

p = Parent()
print p.grandma_name

child = Child()

print child.grandma_name

In each class that you need to inherit from, you can run a loop of each class that needs init’d upon initiation of the child class…an example that can copied might be better understood…

class Female_Grandparent:
    def __init__(self):
        self.grandma_name = 'Grandma'

class Male_Grandparent:
    def __init__(self):
        self.grandpa_name = 'Grandpa'

class Parent(Female_Grandparent, Male_Grandparent):
    def __init__(self):
        Female_Grandparent.__init__(self)
        Male_Grandparent.__init__(self)

        self.parent_name = 'Parent Class'

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
#---------------------------------------------------------------------------------------#
        for cls in Parent.__bases__: # This block grabs the classes of the child
             cls.__init__(self)      # class (which is named 'Parent' in this case), 
                                     # and iterates through them, initiating each one.
                                     # The result is that each parent, of each child,
                                     # is automatically handled upon initiation of the 
                                     # dependent class. WOOT WOOT! :D
#---------------------------------------------------------------------------------------#



g = Female_Grandparent()
print g.grandma_name

p = Parent()
print p.grandma_name

child = Child()

print child.grandma_name

回答 2

您实际上不必调用__init__基类的方法,但是通常您希望这样做,因为基类将在其中进行一些重要的初始化,而其余的类方法都需要进行初始化。

对于其他方法,这取决于您的意图。如果只想向基类行为添加某些内容,则需要在自己的代码中另外调用基类方法。如果要从根本上改变行为,则可以不调用基类的方法,而直接在派生类中实现所有功能。

You don’t really have to call the __init__ methods of the base class(es), but you usually want to do it because the base classes will do some important initializations there that are needed for rest of the classes methods to work.

For other methods it depends on your intentions. If you just want to add something to the base classes behavior you will want to call the base classes method additionally to your own code. If you want to fundamentally change the behavior, you might not call the base class’ method and implement all the functionality directly in the derived class.


回答 3

如果FileInfo类具有多个祖先类,则您绝对应该调用其所有__init __()函数。您还应该对__del __()函数(该函数是析构函数)执行相同的操作。

If the FileInfo class has more than one ancestor class then you should definitely call all of their __init__() functions. You should also do the same for the __del__() function, which is a destructor.


回答 4

是的,您必须调用__init__每个家长班。如果要覆盖两个父级中都存在的功能,则功能也是如此。

Yes, you must call __init__ for each parent class. The same goes for functions, if you are overriding a function that exists in both parents.


为什么不自动调用超类__init__方法?

问题:为什么不自动调用超类__init__方法?

为什么Python设计人员会决定子类的__init__()方法不会__init__()像某些其他语言那样自动调用其超类的方法?Pythonic和推荐的习语真的像下面这样吗?

class Superclass(object):
    def __init__(self):
        print 'Do something'

class Subclass(Superclass):
    def __init__(self):
        super(Subclass, self).__init__()
        print 'Do something else'

Why did the Python designers decide that subclasses’ __init__() methods don’t automatically call the __init__() methods of their superclasses, as in some other languages? Is the Pythonic and recommended idiom really like the following?

class Superclass(object):
    def __init__(self):
        print 'Do something'

class Subclass(Superclass):
    def __init__(self):
        super(Subclass, self).__init__()
        print 'Do something else'

回答 0

Python __init__与其他语言的构造函数之间的关键区别在于,__init__不是构造函数:它是一个初始化程序(实际的构造函数(如果有,但是请参阅下文;-)是__new__并且再次完全不同。虽然构建所有超(,毫无疑问,这样做,你继续向下构建“之前”)显然是说你的一部分构建一个子类的实例,这显然是不适合的情况下初始化,因为在许多用例中,超类的初始化需要被跳过,更改和控制-发生在子类初始化的“中间”,如果发生的话,等等。

基本上,出于完全相同的原因,初始化程序的超类委派在Python中不是自动的,此类委派对于任何其他方法也不是自动的-请注意,那些“其他语言” 对任何其他方法都不会自动进行超类委派其他方法… 只是针对构造函数(如果适用,也应包含析构函数),正如我提到的,这不是 Python的__init__方法。(的行为__new__也很特殊,尽管实际上与您的问题没有直接关系,因为它__new__是一个奇特的构造函数,实际上并不一定要构造任何东西-可以很好地返回一个现有实例,甚至一个非实例…显然Python为您提供了很多比您要记住的“其他语言”,对机械的控制更多,它本身没有自动委派__new__!-)。

The crucial distinction between Python’s __init__ and those other languages constructors is that __init__ is not a constructor: it’s an initializer (the actual constructor (if any, but, see later;-) is __new__ and works completely differently again). While constructing all superclasses (and, no doubt, doing so “before” you continue constructing downwards) is obviously part of saying you’re constructing a subclass’s instance, that is clearly not the case for initializing, since there are many use cases in which superclasses’ initialization needs to be skipped, altered, controlled — happening, if at all, “in the middle” of the subclass initialization, and so forth.

Basically, super-class delegation of the initializer is not automatic in Python for exactly the same reasons such delegation is also not automatic for any other methods — and note that those “other languages” don’t do automatic super-class delegation for any other method either… just for the constructor (and if applicable, destructor), which, as I mentioned, is not what Python’s __init__ is. (Behavior of __new__ is also quite peculiar, though really not directly related to your question, since __new__ is such a peculiar constructor that it doesn’t actually necessarily need to construct anything — could perfectly well return an existing instance, or even a non-instance… clearly Python offers you a lot more control of the mechanics than the “other languages” you have in mind, which also includes having no automatic delegation in __new__ itself!-).


回答 1

当人们模仿“ Python禅”时,我有些尴尬,好像这是任何事情的正当理由。这是一种设计理念;特定的设计决策总是可以用更具体的术语来解释-必须如此,否则“ Zen of Python”将成为做任何事情的借口。

原因很简单:您不必以与构造基类的方式完全相似的方式构造派生类。您可能有更多的参数,更少的参数,它们的顺序可能不同或根本不相关。

class myFile(object):
    def __init__(self, filename, mode):
        self.f = open(filename, mode)
class readFile(myFile):
    def __init__(self, filename):
        super(readFile, self).__init__(filename, "r")
class tempFile(myFile):
    def __init__(self, mode):
        super(tempFile, self).__init__("/tmp/file", mode)
class wordsFile(myFile):
    def __init__(self, language):
        super(wordsFile, self).__init__("/usr/share/dict/%s" % language, "r")

这适用于所有派生方法,而不仅仅是__init__

I’m somewhat embarrassed when people parrot the “Zen of Python”, as if it’s a justification for anything. It’s a design philosophy; particular design decisions can always be explained in more specific terms–and they must be, or else the “Zen of Python” becomes an excuse for doing anything.

The reason is simple: you don’t necessarily construct a derived class in a way similar at all to how you construct the base class. You may have more parameters, fewer, they may be in a different order or not related at all.

class myFile(object):
    def __init__(self, filename, mode):
        self.f = open(filename, mode)
class readFile(myFile):
    def __init__(self, filename):
        super(readFile, self).__init__(filename, "r")
class tempFile(myFile):
    def __init__(self, mode):
        super(tempFile, self).__init__("/tmp/file", mode)
class wordsFile(myFile):
    def __init__(self, language):
        super(wordsFile, self).__init__("/usr/share/dict/%s" % language, "r")

This applies to all derived methods, not just __init__.


回答 2

Java和C ++ 要求由于内存布局而调用基类构造函数。

如果您有一个BaseClass包含成员的类field1,并且创建了一个SubClass添加成员的新类field2,则的实例SubClass包含field1和的空间field2。您需要一个的构造函数BaseClass来填充field1,除非您需要所有继承的类BaseClass在其自己的构造函数中重复的初始化。如果field1是私有的,那么继承类将无法初始化field1

Python不是Java或C ++。所有用户定义类的所有实例都具有相同的“形状”。它们基本上只是可​​以在其中插入属性的字典。在完成任何初始化之前,所有用户定义类的所有实例几乎完全相同;它们只是存储尚未存储的属性的地方。

因此,对于Python子类而言,不调用其基类构造函数是很有意义的。如果需要,它可以只添加属性本身。对于层次结构中的每个类,没有为给定数目的字段保留空间,并且通过BaseClass方法中的代码添加的属性与通过方法中的代码添加的属性之间没有区别SubClass

如果像通常一样,SubClass实际上确实希望BaseClass在继续进行自己的自定义之前设置所有的不变式,那么可以调用BaseClass.__init__()(或使用)super,但这是很复杂的,并且有时会出现自己的问题。但是您不必。您可以在之前,之后或使用其他参数来执行此操作。地狱,如果你想的话,可以BaseClass.__init__完全从另一个方法而不是__init__; 调用。也许您正在进行一些奇怪的懒惰初始化操作。

Python通过保持简单而实现了这种灵活性。通过编写在__init__上设置属性的方法来初始化对象self。而已。它的行为与方法完全一样,因为它正是方法。对于必须首先完成的事情,或者如果您不执行其他操作会自动发生的事情,没有其他奇怪而又不直观的规则。它唯一需要服务的目的是成为一个在对象初始化期间执行的钩子,以设置初始属性值,而它正是这样做的。如果您希望它做其他事情,则可以在代码中显式地编写。

Java and C++ require that a base class constructor is called because of memory layout.

If you have a class BaseClass with a member field1, and you create a new class SubClass that adds a member field2, then an instance of SubClass contains space for field1 and field2. You need a constructor of BaseClass to fill in field1, unless you require all inheriting classes to repeat BaseClass‘s initialization in their own constructors. And if field1 is private, then inheriting classes can’t initialise field1.

Python is not Java or C++. All instances of all user-defined classes have the same ‘shape’. They’re basically just dictionaries in which attributes can be inserted. Before any initialisation has been done, all instances of all user-defined classes are almost exactly the same; they’re just places to store attributes that aren’t storing any yet.

So it makes perfect sense for a Python subclass not to call its base class constructor. It could just add the attributes itself if it wanted to. There’s no space reserved for a given number of fields for each class in the hierarchy, and there’s no difference between an attribute added by code from a BaseClass method and an attribute added by code from a SubClass method.

If, as is common, SubClass actually does want to have all of BaseClass‘s invariants set up before it goes on to do its own customisation, then yes you can just call BaseClass.__init__() (or use super, but that’s complicated and has its own problems sometimes). But you don’t have to. And you can do it before, or after, or with different arguments. Hell, if you wanted you could call the BaseClass.__init__ from another method entirely than __init__; maybe you have some bizarre lazy initialization thing going.

Python achieves this flexibility by keeping things simple. You initialise objects by writing an __init__ method that sets attributes on self. That’s it. It behaves exactly like a method, because it is exactly a method. There are no other strange and unintuitive rules about things having to be done first, or things that will automatically happen if you don’t do other things. The only purpose it needs to serve is to be a hook to execute during object initialisation to set initial attribute values, and it does just that. If you want it to do something else, you explicitly write that in your code.


回答 3

“显式比隐式好。” 同样的道理表明我们应该明确地写出“自我”。

最后,我认为这是有好处的-您能列举一下Java关于调用超类的构造函数的所有规则吗?

“Explicit is better than implicit.” It’s the same reasoning that indicates we should explicitly write ‘self’.

I think in in the end it is a benefit– can you recite all of the rules Java has regarding calling superclasses’ constructors?


回答 4

通常,子类具有无法传递给超类的额外参数。

Often the subclass has extra parameters which can’t be passed to the superclass.


回答 5

现在,我们有一个较长的页面描述了多重继承的情况下方法解析的顺序:http : //www.python.org/download/releases/2.3/mro/

如果自动调用了构造函数,则需要另一页至少具有相同长度的页面,以解释其发生的顺序。那将是地狱…

Right now, we have a rather long page describing the method resolution order in case of multiple inheritance: http://www.python.org/download/releases/2.3/mro/

If constructors were called automatically, you’d need another page of at least the same length explaining the order of that happening. That would be hell…


回答 6

为了避免混淆,知道__init__()child_class没有__init__()类时可以调用base_class 方法是很有用的。

例:

class parent:
  def __init__(self, a=1, b=0):
    self.a = a
    self.b = b

class child(parent):
  def me(self):
    pass

p = child(5, 4)
q = child(7)
z= child()

print p.a # prints 5
print q.b # prints 0
print z.a # prints 1

实际上,__init__()当在子类中找不到它时,python中的MRO会在父类中查找。如果子类中已经有一个__init__()方法,则需要直接调用父类的构造函数。

例如,以下代码将返回错误:class parent:def init(self,a = 1,b = 0):self.a = a self.b = b

    class child(parent):
      def __init__(self):
        pass
      def me(self):
        pass

    p = child(5, 4) # Error: constructor gets one argument 3 is provided.
    q = child(7)  # Error: constructor gets one argument 2 is provided.

    z= child()
    print z.a # Error: No attribute named as a can be found.

To avoid confusion it is useful to know that you can invoke the base_class __init__() method if the child_class does not have an __init__() class.

Example:

class parent:
  def __init__(self, a=1, b=0):
    self.a = a
    self.b = b

class child(parent):
  def me(self):
    pass

p = child(5, 4)
q = child(7)
z= child()

print p.a # prints 5
print q.b # prints 0
print z.a # prints 1

In fact the MRO in python will look for __init__() in the parent class when can not find it in the children class. You need to invoke the parent class constructor directly if you have already an __init__() method in the children class.

For example the following code will return an error: class parent: def init(self, a=1, b=0): self.a = a self.b = b

    class child(parent):
      def __init__(self):
        pass
      def me(self):
        pass

    p = child(5, 4) # Error: constructor gets one argument 3 is provided.
    q = child(7)  # Error: constructor gets one argument 2 is provided.

    z= child()
    print z.a # Error: No attribute named as a can be found.

回答 7

也许__init__是子类需要重写的方法。有时,子类在添加特定于类的代码之前需要运行父级函数,而有时,它们需要在调用父级函数之前设置实例变量。由于Python不可能知道何时最适合调用这些函数,因此不应该猜测。

如果这些都不影响您,请考虑这__init__只是另一个功能。如果有问题的函数dostuff代替了,您是否仍然希望Python在父类中自动调用相应的函数?

Maybe __init__ is the method that the subclass needs to override. Sometimes subclasses need the parent’s function to run before they add class-specific code, and other times they need to set up instance variables before calling the parent’s function. Since there’s no way Python could possibly know when it would be most appropriate to call those functions, it shouldn’t guess.

If those don’t sway you, consider that __init__ is Just Another Function. If the function in question were dostuff instead, would you still want Python to automatically call the corresponding function in the parent class?


回答 8

我相信这里一个非常重要的考虑因素是,通过自动调用super.__init__(),您可以按设计禁止在何时调用该初始化方法以及使用哪些参数。避免自动调用它,并要求程序员明确地执行该调用,需要很大的灵活性。

毕竟,仅因为类B派生自类A并不意味着A.__init__()可以或应该使用与相同的参数进行调用B.__init__()。将调用明确化意味着程序员可以例如B.__init__()使用完全不同的参数进行定义,使用该数据进行一些计算,A.__init__()使用适合该方法的参数进行调用,然后进行一些后处理。如果A.__init__()B.__init__()B.__init__()执行之前或执行之后隐式调用,则很难获得这种灵活性。

i believe the one very important consideration here is that with an automatic call to super.__init__(), you proscribe, by design, when that initialization method is called, and with what arguments. eschewing automatically calling it, and requiring the programmer to explicitly do that call, entails a lot of flexibility.

after all, just because class B is derived from class A does not mean A.__init__() can or should be called with the same arguments as B.__init__(). making the call explicit means a programmer can have e.g. define B.__init__() with completely different parameters, do some computation with that data, call A.__init__() with arguments as appropriate for that method, and then do some postprocessing. this kind of flexibility would be awkward to attain if A.__init__() would be called from B.__init__() implicitly, either before B.__init__() executes or right after it.


对于新样式的类,super()引发“ TypeError:必须为类型,而不是classobj”

问题:对于新样式的类,super()引发“ TypeError:必须为类型,而不是classobj”

以下用法super()引发TypeError:为什么?

>>> from  HTMLParser import HTMLParser
>>> class TextParser(HTMLParser):
...     def __init__(self):
...         super(TextParser, self).__init__()
...         self.all_data = []
...         
>>> TextParser()
(...)
TypeError: must be type, not classobj

在StackOverflow上有一个类似的问题:Python super()引发TypeError,该错误由用户类不是新型类的事实来解释。但是,上面的类是一种新式的类,因为它继承自object

>>> isinstance(HTMLParser(), object)
True

我想念什么?我如何super()在这里使用?

使用HTMLParser.__init__(self)代替super(TextParser, self).__init__()可以工作,但是我想了解TypeError。

PS:Joachim指出,成为一个新类实例并不等同于成为一个实例object。我读了很多相反的书,因此感到困惑(基于object实例测试的新型类实例测试的示例:https : //stackoverflow.com/revisions/2655651/3)。

The following use of super() raises a TypeError: why?

>>> from  HTMLParser import HTMLParser
>>> class TextParser(HTMLParser):
...     def __init__(self):
...         super(TextParser, self).__init__()
...         self.all_data = []
...         
>>> TextParser()
(...)
TypeError: must be type, not classobj

There is a similar question on StackOverflow: Python super() raises TypeError, where the error is explained by the fact that the user class is not a new-style class. However, the class above is a new-style class, as it inherits from object:

>>> isinstance(HTMLParser(), object)
True

What am I missing? How can I use super(), here?

Using HTMLParser.__init__(self) instead of super(TextParser, self).__init__() would work, but I would like to understand the TypeError.

PS: Joachim pointed out that being a new-style-class instance is not equivalent to being an object. I read the opposite many times, hence my confusion (example of new-style class instance test based on object instance test: https://stackoverflow.com/revisions/2655651/3).


回答 0

好吧,这是通常的“ super()不能与老式类一起使用”。

但是,重要的一点是对“这是一个新的实例(即对象)吗?” 的正确测试。是

>>> class OldStyle: pass
>>> instance = OldStyle()
>>> issubclass(instance.__class__, object)
False

而不是(如问题所示):

>>> isinstance(instance, object)
True

对于,正确的“这是新型类”测试是:

>>> issubclass(OldStyle, object)  # OldStyle is not a new-style class
False
>>> issubclass(int, object)  # int is a new-style class
True

关键的一点是,与老式类的的实例和它的类型是不同的。在这里,OldStyle().__class__is OldStyle,它不继承自object,而type(OldStyle())is instance类型,它确实继承自object。基本上,旧式类仅创建类型的对象instance(而新式类将创建类型为类本身的对象)。这大概就是为什么实例OldStyle()object:其type()从继承object(事实上,它的类并没有继承object不计数:老式类只是构建类型的新对象instance)。部分参考:https://stackoverflow.com/a/9699961/42973

PS:新式类和旧式类之间的区别还可以通过以下方式看到:

>>> type(OldStyle)  # OldStyle creates objects but is not itself a type
classobj
>>> isinstance(OldStyle, type)
False
>>> type(int)  # A new-style class is a type
type

(旧式类不是类型,因此它们不能是其实例的类型)。

Alright, it’s the usual “super() cannot be used with an old-style class”.

However, the important point is that the correct test for “is this a new-style instance (i.e. object)?” is

>>> class OldStyle: pass
>>> instance = OldStyle()
>>> issubclass(instance.__class__, object)
False

and not (as in the question):

>>> isinstance(instance, object)
True

For classes, the correct “is this a new-style class” test is:

>>> issubclass(OldStyle, object)  # OldStyle is not a new-style class
False
>>> issubclass(int, object)  # int is a new-style class
True

The crucial point is that with old-style classes, the class of an instance and its type are distinct. Here, OldStyle().__class__ is OldStyle, which does not inherit from object, while type(OldStyle()) is the instance type, which does inherit from object. Basically, an old-style class just creates objects of type instance (whereas a new-style class creates objects whose type is the class itself). This is probably why the instance OldStyle() is an object: its type() inherits from object (the fact that its class does not inherit from object does not count: old-style classes merely construct new objects of type instance). Partial reference: https://stackoverflow.com/a/9699961/42973.

PS: The difference between a new-style class and an old-style one can also be seen with:

>>> type(OldStyle)  # OldStyle creates objects but is not itself a type
classobj
>>> isinstance(OldStyle, type)
False
>>> type(int)  # A new-style class is a type
type

(old-style classes are not types, so they cannot be the type of their instances).


回答 1

super()仅可用于新型类,这意味着根类需要从’object’类继承。

例如,顶级类需要像这样:

class SomeClass(object):
    def __init__(self):
        ....

class SomeClass():
    def __init__(self):
        ....

因此,解决方案是直接调用父级的init方法,如下所示:

class TextParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.all_data = []

super() can be used only in the new-style classes, which means the root class needs to inherit from the ‘object’ class.

For example, the top class need to be like this:

class SomeClass(object):
    def __init__(self):
        ....

not

class SomeClass():
    def __init__(self):
        ....

So, the solution is that call the parent’s init method directly, like this way:

class TextParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.all_data = []

回答 2

您也可以使用class TextParser(HTMLParser, object):。这将创建TextParser一个新样式的类,并且super()可以使用。

You can also use class TextParser(HTMLParser, object):. This makes TextParser a new-style class, and super() can be used.


回答 3

问题是super需要object一个祖先:

>>> class oldstyle:
...     def __init__(self): self.os = True

>>> class myclass(oldstyle):
...     def __init__(self): super(myclass, self).__init__()

>>> myclass()
TypeError: must be type, not classobj

经过仔细检查,发现:

>>> type(myclass)
classobj

但:

>>> class newstyle(object): pass

>>> type(newstyle)
type    

因此,解决您的问题的方法是从对象以及HTMLParser继承。但是确保对象在MRO类中排在最后:

>>> class myclass(oldstyle, object):
...     def __init__(self): super(myclass, self).__init__()

>>> myclass().os
True

The problem is that super needs an object as an ancestor:

>>> class oldstyle:
...     def __init__(self): self.os = True

>>> class myclass(oldstyle):
...     def __init__(self): super(myclass, self).__init__()

>>> myclass()
TypeError: must be type, not classobj

On closer examination one finds:

>>> type(myclass)
classobj

But:

>>> class newstyle(object): pass

>>> type(newstyle)
type    

So the solution to your problem would be to inherit from object as well as from HTMLParser. But make sure object comes last in the classes MRO:

>>> class myclass(oldstyle, object):
...     def __init__(self): super(myclass, self).__init__()

>>> myclass().os
True

回答 4

如果您查看继承树(在2.6版中),则HTMLParser继承自SGMLParser,继承自ParserBase而不继承自object。即HTMLParser是一个老式的类。

关于您的检查isinstance,我在ipython中进行了快速测试:

在[1]中:A类:
   ...:通过
   ...: 

在[2]中:isinstance(A,object)
出[2]:是

即使一个类是老式类,它仍然是的一个实例object

If you look at the inheritance tree (in version 2.6), HTMLParser inherits from SGMLParser which inherits from ParserBase which doesn’t inherits from object. I.e. HTMLParser is an old-style class.

About your checking with isinstance, I did a quick test in ipython:

In [1]: class A:
   ...:     pass
   ...: 

In [2]: isinstance(A, object)
Out[2]: True

Even if a class is old-style class, it’s still an instance of object.


回答 5

正确的方法是在不继承自’object’的旧类中执行以下操作

class A:
    def foo(self):
        return "Hi there"

class B(A):
    def foo(self, name):
        return A.foo(self) + name

the correct way to do will be as following in the old-style classes which doesn’t inherit from ‘object’

class A:
    def foo(self):
        return "Hi there"

class B(A):
    def foo(self, name):
        return A.foo(self) + name

回答 6

FWIW,尽管我不是Python专家,但我对此很满意

>>> class TextParser(HTMLParser):
...    def handle_starttag(self, tag, attrs):
...        if tag == "b":
...            self.all_data.append("bold")
...        else:
...            self.all_data.append("other")
...     
...         
>>> p = TextParser()
>>> p.all_data = []
>>> p.feed(text)
>>> print p.all_data
(...)

只是让我根据需要返回解析结果。

FWIW and though I’m no Python guru I got by with this

>>> class TextParser(HTMLParser):
...    def handle_starttag(self, tag, attrs):
...        if tag == "b":
...            self.all_data.append("bold")
...        else:
...            self.all_data.append("other")
...     
...         
>>> p = TextParser()
>>> p.all_data = []
>>> p.feed(text)
>>> print p.all_data
(...)

Just got me the parse results back as needed.