Python中的重写与虚拟类方法

时间:2014-04-09 17:34:25

标签: python class oop python-2.7 inheritance

据我所知,在Python中,父类的方法被覆盖。 因此,默认情况下所有类方法都是虚拟的,如下面的代码所示。

class Parent(object):

    def Method1(self):
        print 'FOO'

class Child(Parent):

    def Method1(self):
        print 'BAR'

myInstance = Child()

#Overridden method is called
myInstance.Method1()                             # BAR

#Is it possible to do the following?
myInstance.{something}                           # FOO

问题:

  • 是否可以从子类的实例Parent.Method1()调用父方法myInstance

  • 是否可以通过具有相同名称的方法覆盖def Parent.Method1(self) 而不是,但是有一些不同的参数集def Child.Method1(self,x,y)

3 个答案:

答案 0 :(得分:2)

通过super()函数搜索MRO中的下一个方法(方法解析顺序)来调用父方法:

class Child(BaseClass):
    def Method1(self):
        print 'BAR'
        super(Child, self).Method1()  # will call BaseClass.Method1

其中self是实例引用,因此super(type(myInstance), myInstance).Method1()将从方法外部实现相同的功能。

或者您可以访问类上的未绑定方法,并明确传入实例;你也可以在方法之外做到这一点:

BaseClass.Method1(myInstance)

因为现在您直接在类上引用了method属性,并将该实例作为显式self传递给该方法;你可以在self那里的方法中使用Child

通过名称查找Python属性(方法也是属性),这样的查找通过实例搜索,然后搜索实例的类,然后搜索每个父类,直到找到匹配为止;方法的签名在这里没有发挥作用。

您仍然可以使用关键字参数覆盖子类中的方法,更改签名,但使用父方法保持兼容

class Child(BaseClass):
    def Method1(self, x=None, y=None):
        if x is None and y is None:
            # arguments left at defaults, call base method
            return super(Child, self).Method1()

        print 'BAR: {} and {}'.format(x, y)

现在,如果你在没有参数的情况下调用myInstance.Method1(),则会调用BaseClass.Method1()方法,传入参数,而是发生其他事情。

答案 1 :(得分:1)

  

是否可以从中调用父方法Parent.Method1()   实例是子类的myInstance?

您可以直接调用该方法,并将您的实例作为第一个参数传递:

>>> class A(object):
...     def foo(self):
...         print 'foo'
...
>>> class B(A):
...     def foo(self):
...         print 'bar'
...
>>> b = B()
>>> A.foo(b)
foo
  

是否可以使def Parent.Method1(self)不被覆盖   通过具有相同名称的方法,但是一些不同的参数集   def Child.Method1(self,x,y)?

是的,您使用super并直接调用父方法:

>>> class A(object):
...     def foo(self, bar='bar'):
...         print bar
...
>>> class B(A):
...     def foo(self):
...         super(B, self).foo(bar='foo')
...
>>> B().foo()
foo
>>> A().foo()
bar

答案 2 :(得分:1)

除了使用super之外,还有一些绕过MRO的显式选项:

# Explicitly call Baseclass.Method1, passing your instance as the argument
BaseClass.Method1(myInstance)

# Call Method1 on the (first) base class of the instance.
# This is ugly; don't actually write code like this
# x.__class__.__bases__[0] is just another way to get a reference
# to BaseClass; otherwise, this is identical to the previous option,
# hence the need to repeat myInstance
myInstance.__class__.__bases__[0].Method1(myInstance)