我们可以在python 2.7中从子类的类方法中调用父类的实例方法吗?

时间:2019-01-14 10:26:13

标签: python python-2.7

In Python 2
class P(object):
  def M1(self): print 'inside P class M1())'
class Q(P):
  def M1(self): print 'inside Q class M1()'
  @classmethod
  def M2(cls):
    super(Q,cls).M1(cls)
s = Q()
s.M2()
----------------In Python3-------
class P(object):
   def M1(self): print ('inside M1 Method of P class')
class Q(P):
  @classmethod
  def M2(cls):
    super().M1(cls) or super(Q,cls)M1(cls)
s = Q()
s.M2()

在Python2中: super(Q,cls).M1(cls)#从这里获取错误,但是我们可以在python 3中使用相同的语句,并且可以正常工作。我只是想知道python 2.7是否可以通过使用super()来调用父类实现的任何类似方法。

`

1 个答案:

答案 0 :(得分:1)

将print语句修改为函数,这似乎可以在Python 3.7内愉快地运行

Python 3.7.1 (default, Dec 10 2018, 22:54:23) [MSC v.1915 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: class P(object):
   ...:     def M1(self): print('inside P')
   ...: class Q(P):
   ...:     def M1(self): print('inside Q')
   ...:     @classmethod
   ...:     def M2(cls):
   ...:         super(Q, cls).M1(cls)
   ...:

In [2]: s = Q()

In [3]: s.M2()
inside P

但是在Python2中失败,并显示错误

  

TypeError:未绑定方法M1()必须以Q实例作为第一个参数(而不是类型实例)调用

正像错误所言,因为M1是一个实例方法,它的参数必须是一个实例,而不是一个类。您可以通过将M1设置为静态并且不使用任何参数来解决此问题。

我怀疑这在Python3中是可行的,因为super()实现中的技巧可以支持方法内部的使用。通读建议中的standard library docsthis很有帮助。

这在Python3中有效,因为它没有断言第一个参数的类型-假定该值合适并且没有遇到错误。鸭子打字的例子。

编辑,对Python 3行为更通用

OP看到的错误实际上并不是由于super()引起的,而是由于Python 3处理实例方法的方式与Python 2不同。

>>> class Foo(object):
>>>     def __init__(self):
>>>         self._bar = 0
>>>     def bar(self): 
>>>         print('baz')
>>>     def boo(self):
>>>         self._bar+=1
>>>         print(self._bar)
>>> f = Foo()
>>> Foo.bar(Foo)  # fine in Python3, TypeError in Python2
>>> Foo.bar(None)  # fine in Python3, TypeError in Python2
>>> f.bar()  # fine in both
baz
>>> Foo.boo(Foo)  # AttributeError in Python3, TypeError in Python2

在这两种情况下,Python2都有一个嵌入式断言,即实例方法的第一个参数必须为匹配类的实例类型。 Python3没有这个断言-它很高兴收到Nonetype类型,至少直到收到的任何参数失效为止。这是ducktyping的一个很好的例子。

因此Foo.bar在Python3中可以使用,因为它实际上并不关心参数的值是什么-它没有使用它。但是,在Foo.boo中,尝试递增AttributeError实例属性时,它失败并显示Foo._bar(因为实例属性在给定的参数中不存在)。