派生类是否自动具有基类的所有属性? [英] Does a derived class automatically have all the attributes of the base class?

查看:131
本文介绍了派生类是否自动具有基类的所有属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于此,似乎没有好的在线文档: 如果创建派生类,它将自动具有基类的所有属性吗?但是BaseClass.__init()的作用是什么,您是否还需要对其他基类方法进行处理? BaseClass.__init__()是否需要参数?如果您有基类__init__()的参数,派生类也使用它们吗,是否需要将参数显式设置为派生类的__init__()或将其设置为BaseClass.__init__()?

There seems to be no good online documentation on this: If I make a derived class, will it automatically have all the attributes of the base class? But what's the BaseClass.__init() for, do you also need to do it to other base class methods? Does BaseClass.__init__() need arguments? If you have arguments for your base class __init__(), are they also used by the derived class, do you need to explicitly set the arguments to the derived classe's __init__(), or set them to BaseClass.__init__() instead?

推荐答案

如果在从BaseClass派生的类中实现__init__,则它将覆盖继承的__init__方法,因此将永远不会调用BaseClass.__init__.如果您需要为BaseClass调用__init__方法(通常是这种情况),则完全由您自己决定,通常在新实现的__init__方法中通过调用BaseClass.__init__来明确地做到这一点.

If you implement __init__ in a class derived from BaseClass, then it will overwrite the inherited __init__ method and so BaseClass.__init__ will never be called. If you need to call the __init__ method for BaseClass (as is normally the case), then its up to you to do that, and its done explicitly by calling BaseClass.__init__, normally from within the newly implemented __init__ method.

class Foo(object):
    def __init__(self):
        self.a = 10

    def do_something(self):
        print self.a

class Bar(Foo):
    def __init__(self):
        self.b = 20

bar = Bar()
bar.do_something()

这将导致以下错误:

AttributeError: 'Bar' object has no attribute 'a'

因此,do_something方法已按预期方式继承,但是该方法要求设置属性a,这绝不是因为__init__也被覆盖了.我们通过在Bar.__init__内部显式调用Foo.__init__来解决这个问题.

So, the do_something method has been inherited as expected, but that method requires the attribute a to have been set, which it never is because __init__ was also overwritten. We get round this by explicitly calling Foo.__init__ from within Bar.__init__.

class Foo(object):
    def __init__(self):
        self.a = 10

    def do_something(self):
        print self.a

class Bar(Foo):
    def __init__(self):
        Foo.__init__(self)
        self.b = 20

bar = Bar()
bar.do_something()

将按预期打印10.在这种情况下,Foo.__init__需要一个单独的参数,该参数是Foo的实例(按照惯例称为self).

which prints 10 as expected. Foo.__init__ in this case expects a single argument which is an instance of Foo (which by convention is called self).

通常,当您在类的实例上调用方法时,该类实例将作为第一个参数自动传递.类实例上的方法称为绑定方法. bar.do_something是绑定方法的示例(并且您会注意到它是在没有任何参数的情况下调用的). Foo.__init__绑定方法,因为它没有附加到Foo的特定实例,因此第一个参数(Foo的实例)需要显式传递.

Normally, when you call a method on an instance of a class, the class instance is passed automatically as the first argument. Methods on an instance of a class are called bound methods. bar.do_something is an example of a bound method (and you'll note that it is called without any arguments). Foo.__init__ is an unbound method because it is not attached to a particular instance of Foo, so the first argument, an instance of Foo, needs to be passed explicitly.

在我们的例子中,我们将self传递给Foo.__init__,这是Bar的实例,该实例已传递给Bar中的__init__方法.由于Bar继承自Foo,因此Bar的实例也是Foo的实例,因此允许将self传递给Foo.__init__.

In our case, we pass self to Foo.__init__, which is the instance of Bar that was passed to the __init__ method in Bar. Since Bar inherits from Foo, instances of Bar are also instances of Foo, so passing self to Foo.__init__ is allowed.

很可能是您从中继承的类需要或接受的参数不仅仅是该类的实例.与在__init__中调用的任何方法一样,对它们进行处理:

It is likely be the case that the class you are inheriting from requires or accepts more arguments than just an instance of the class. These are dealt with as you would with any method you're calling from within __init__:

class Foo(object):
    def __init__(self, a=10):
        self.a = a

    def do_something(self):
        print self.a

class Bar(Foo):
    def __init__(self):
        Foo.__init__(self, 20)

bar = Bar()
bar.do_something()

将显示20.

如果您试图实现一个通过继承类完全暴露基类的所有初始化参数的接口,则需要明确地这样做.通常使用* args和** kwargs参数(名称是按惯例)完成的,这些参数是未明确命名的所有其他参数的占位符.以下示例充分利用了我所讨论的一切:

If you're trying to implement a interface that fully exposes all the initialisation arguments of the base class through your inheriting class, you'll need to do so explicitly. This is typically done with the *args and **kwargs arguments (the names are by convention), which are placeholders for all rest of the arguments that aren't explicitly named. The following example makes use of everything I've discussed:

class Foo(object):
    def __init__(self, a, b=10):
        self.num = a * b

    def do_something(self):
        print self.num

class Bar(Foo):
    def __init__(self, c=20, *args, **kwargs):
        Foo.__init__(self, *args, **kwargs)
        self.c = c

    def do_something(self):
        Foo.do_something(self)
        print self.c


bar = Bar(40, a=15)
bar.do_something()

在这种情况下,参数c设置为40,因为它是Bar.__init__的第一个参数.然后将第二个参数合并到变量argskwargs中(*和**是特定语法,表示将列表/元组或字典扩展为传递给函数/方法时的单独参数),并继续传递到Foo.__init__.

In this case, the argument c is set to be 40, as it's the first argument to Bar.__init__. The second argument is then incorporated into the variables args and kwargs (the * and ** is specific syntax that says expand the list/tuple or dictionary into separate arguments when passing to a function/method), and is passed on to Foo.__init__.

此示例还指出,如果需要,必须显式调用任何覆盖的方法(在这种情况下为do_something).

This example also makes the point that any overwritten method needs to be called explicitly if that is what is required (as do_something is in this case).

最后一点,您经常会看到使用了super(ChildClass, self).method()(其中ChildClass是任意子类),而不是显式地调用BaseClass方法.对super的讨论是另一个完全不同的问题,但足以说,在这些情况下,通常使用它来完全通过调用BaseClass.method(self)来完成所要执行的操作.简而言之,super将方法调用按方法解析顺序委派给下一个类-MRO(在单个继承中为父类).有关更多信息,请参见有关super的文档.

One final point, you will often see super(ChildClass, self).method() (where ChildClass is some arbitrary child class) being used instead of a call to the BaseClass method explicitly. Discussion of super is a whole other question, but suffice it to say, in these cases it's typically being used to do exactly what is being done by calling BaseClass.method(self). Briefly, super delegates the method call to the next class in the method resolution order - the MRO (which in single inheritance is the parent class). See the documentation on super for more info.

这篇关于派生类是否自动具有基类的所有属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆