简体   繁体   中英

Can we call instance method of parent class from class method of child class in 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()

In Python2: super(Q,cls).M1(cls)#Getting error from here,But we can use same statement in python 3 and it works . I just wondering whether python 2.7 can have any similar way to call parent class implementation by using super() or not .

`

Modifying the print statements to functions, this seems to run happily inside of 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

But fails in Python2 with the error

TypeError: unbound method M1() must be called with Q instance as first argument (got type instance instead)

Exactly as the error says, because M1 is an instance method its argument must be an instance, not a class. You can get around this by making M1 static and take no arguments.

I suspect this works in Python3 because of tricks inside the implementation of super() to support usage inside of methods. Reading through the standard library docs and this recommended post were helpful.

This works in Python3 because it doesn't assert the type of the first argument -- it assumes the value is suitable and doesn't hit an error. An example of duck typing.

Edit, more general to Python 3 behavior

The error OP is seeing is not actually due to super() but due to how Python 3 handles instance methods differently than Python 2. An example class could be

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

In both cases for, Python2 has an embedded assertion that the first argument of an instance method must be an instance type of the matching class. Python3 does not have this assertion for -- it's happy receiving None or a type type, at least until whatever argument it received fails to work. This is a great example of ducktyping .

So Foo.bar works in Python3 because it doesn't actually care what the value of the argument is -- it doesn't use it. In Foo.boo , however, it fails with an AttributeError when trying to increment the Foo._bar instance property (because that instance property doesn't exist in the argument it was given).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM