-2

I have one simple doubt with respect to python 2.7:

I have created an abstract base class and a child class:

from abc import ABCMeta, abstractmethod


class Base:

    """
    Abstract base class for all entities.
    """
    __metaclass__ = ABCMeta

    def __init__(self, name):
        self.name = name

    def send_data(self):
        self.send_data()

class Child (Base):

    def __init__(self, name):
        super(Child, self).__init__(name=name)

When the object for the child class is created and the send_method is called I get the following error which is the expected behavior:

sample = Child('test')
sample.send_data()

# …
RuntimeError: maximum recursion depth exceeded

But when the send_method reference is passed in the base class and call is made to send_method by creating the child class object I think the expected behavior is to receive AttributeError but I am surprised to see no error is generated. Please explain.

from abc import ABCMeta, abstractmethod

class Base:

    """
    Abstract base class for all entities.
    """
    __metaclass__ = ABCMeta

    def __init__(self, name, parent):
        self.name = name
        self.parent = parent

    def send_data(self):
        self.send_data

sample = Child('test')
sample.send_data()

# No error
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
vKohli
  • 97
  • 1
  • 7
  • I'm not sure why you expected to get an attribute error. You *have* an attribute `send_data`; the `Base.send_data` method is an attribute. – Martijn Pieters Sep 17 '16 at 16:13

1 Answers1

0

In your first example you simply created a recursive function:

def send_data(self):
    self.send_data()

This calls itself, without end, and that's why you end up with a recursion depth exception.

Your second example doesn't actually call the method:

def send_data(self):
    self.send_data

The only difference here is that you forgot to use ().

None of this has anything to do with abstract base classes or inheritance. You didn't mark the send_data function as abstract, and even if you did, all that using abstractmethod does is make it impossible to create an instance of a class without a concrete implementation to replace it.

You won't get an AttributeError just because you defined a method on an ABCMeta class. And note that methods are just attributes on a class; they don't live a separate namespace. self.send_data references the bound method, not some other attribute that is separate. Referencing the method without calling it does nothing otherwise.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • @vKohli: no it won't, because `instance.send_data()` would find the overridden implementation, not the one on the parent class. – Martijn Pieters Sep 17 '16 at 16:31
  • @vKohli: `self` is just another reference to the instance. Normal attribute lookup rules apply; first look at the instance attributes, then the class in MRO order. So if `send_data` doesn't exist on the instance, `Child.send_data` is found. It doesn't matter if `Base.send_data` then exists. If there is no `Child.send_data`, `Base.send_data` is found. Within a method, `self` is still the same instance, so inside `Base.send_data`, the reference `self.send_data` finds the exact same method again. – Martijn Pieters Sep 17 '16 at 16:33
  • Thanks a lot your explanation is far better than the question I asked. I'm a newbie to python and now I get it that child.send_data will be referred before MRO order. I have one more doubt self.send_data refers to the method send_data() it doesn't get called but just to be sure it is not a new attribute still ? – vKohli Sep 17 '16 at 16:49
  • @vKohli: it is not a new attribute; `self.send_data` is just a reference to the method; you could store it in a variable and later call it too. – Martijn Pieters Sep 17 '16 at 17:10
  • Thanks for the explanation. – vKohli Sep 17 '16 at 21:16