Python中的重写与虚拟类方法

1 投票
3 回答
820 浏览
提问于 2025-04-18 02:04

根据我的理解,在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

问题:

  • 从子类的实例myInstance中,能否调用父类的方法Parent.Method1()

  • 有没有办法让def Parent.Method1(self)不被同名但参数不同的方法def Child.Method1(self,x,y)覆盖?

3 个回答

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)
1

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

你可以直接调用这个方法,并把你的实例作为第一个参数传进去:

>>> 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

你可以通过使用 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)

因为这时候你是直接引用了类中的方法属性,并将实例作为明确的 self 传入这个方法;在 Child 类的方法内部,你会使用 self

在 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() 方法;如果传入参数,情况就会有所不同。

撰写回答