Python: 如何继承并重写父类方法

15

考虑以下情况:

我获取了一个类型为 A 的对象,它具有函数 f

class A:
   def f(self):
      print 'in f'
   def h(self):
      print 'in h'

我得到了这个类的一个实例,但我想重写 f 函数,同时保留 A 的其余功能。所以我想的是类似于以下的东西:

class B(A):
     def __init__(self, a):
        #something here
     ....

     def f(self):
         print 'in B->f'

用法如下:

def main(a):
   b = B(a)
   b.f()   #prints "in B->f"
   b.h()   #print "in h"
我想实现一种类似于拷贝构造函数的东西,它可以获取当前类(A)的父类,并返回此类(B)的一个实例。
如何实现这样的功能?__init__方法应该如何实现?
注意:本帖已经由原帖编辑以包含评论中提出的更改建议,因此某些建议看起来可能是多余或不正确的。

a 应该代表什么? - SilentGhost
2
你需要先了解__init__()方法,Guy。不要将其与继承语法混淆。 - Xavier Ho
3个回答

11

构造一个子类 B 的对象,“基于”类 A 中的一个对象,完全取决于后者如何保留状态(如果有的话),以及如何最好地获取并复制该状态。在您的例子中,A 的实例是无状态的,因此在 B'__init__' 中不需要做任何工作。在更典型的示例中,例如:

class A(object):
   def __init__(self):
     self._x = 23
     self._y = 45
   def f(self):
      print 'in f,', self._x
   def h(self):
      print 'in h,', self._y

状态将位于两个实例属性_x_y中,因此这就是您需要复制的内容:

class B(A):
     def __init__(self, a):
        self._x = a._x
        self._y = a._y

     def f(self):
         print 'in B->f,', self._x

这是最常见、最正常的方法,其中子类接受并直接实现其对父类状态的依赖 —— 这非常简单和线性。

通常在 A'__init__' 中查找 A 实例状态方面的信息,因为大多数常规的、简单的 Python 代码在初始化时建立实例状态(属性可能稍后添加和删除甚至在类体外的代码中进行,但这不是常见的,通常也不可取)。

可以添加一点点"魔法"(基于内省的编程),例如...:

class B1(A):
    def __init__(self, a):
        try: s = a.__getstate__()
        except AttributeError: s = a.__dict__
        try: self.__setstate__(s)
        except AttributeError: self.__dict__.update(s)

getstate 是一个特殊的方法,类可以定义它。如果定义了这个方法,它将被(例如通过pickle)用于获取序列化目的下实例的状态(否则,实例的__dict__被视为实例的“状态”)。如果它返回一个字典,则update调用会更新self的状态;但如果类还定义了一个接受任何其他类型参数的__setstate__方法(因此此代码首先尝试该路线,然后退回到update可能性),那么它也可以返回其他任何东西。请注意,在这种使用情况下,特殊方法中的任一或两者都将从A继承-我不会在B中定义/覆盖它们(当然,除非有进一步微妙的目标要通过这种方式实现)。

是否值得使用这四行"神奇"代码来代替我最初建议的简单赋值呢?大多数情况下不值得——简单性是首选。但如果A做任何特殊操作或受外部代码影响其状态,那么这个解决方案可能更强大且更通用(这正是您通过接受其复杂性购买的)。因此,您必须知道是否适用于后一种情况(然后“使用特殊状态相关方法的大炮”),或者A及其实例是“非常正常的普通实例”,在这种情况下,我强烈建议选择简单和清晰。


+1 - 我今天读到的最有用的东西:“取决于...后者如何保持状态以及你如何将其复制过去” - deadly

5

试试这个:

class A:
  def f(self):
    print("in f")

  def h(self):
    print("in h")

class B(A):
  def f(self):
    print("in B:f")

def test(x):
  x.f()
  x.h()

test(A())
test(B())

注意,我使用的是Python 3,这就是print需要用括号括起来的原因。
输出:
in f
in h
in B:f
in h

1
它和原帖的代码有什么不同呢?看起来他只是忘记了 self - SilentGhost
顺便问一下,在 Python 中方法被声明为虚拟的是什么意思? - Bunny Rabbit
1
@Bunny Rabbit:Douglas 的意思是 virtual,就像在 C++ 中一样,你必须明确地将一个方法定义为 virtual 才能使它可以被覆盖。 - Xavier Ho

2

在Python中,对于实例方法,需要将self参数放入参数列表中。

一旦这样做了,它就能正常工作了,因为在Python中所有的方法都是虚拟的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接