Python 传递方法引用时未生成AttributeError

Python 传递方法引用时未生成AttributeError,python,abstract-base-class,Python,Abstract Base Class,关于python 2.7,我有一个简单的疑问: 我创建了一个抽象基类和一个子类: from abc import ABCMeta, abstractmethod class Base: """ Abstract base class for all entities. """ __metaclass__ = ABCMeta def __init__(self, name): self.name = name def sen

关于python 2.7,我有一个简单的疑问:

我创建了一个抽象基类和一个子类:

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)
创建子类的对象并调用send_方法时,我得到以下错误,这是预期的行为:

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

# …
RuntimeError: maximum recursion depth exceeded
但是,当在基类中传递send_方法引用并通过创建子类对象调用send_方法时,我认为预期的行为是接收AttributeError,但我惊讶地发现没有生成错误。请解释一下

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

在第一个示例中,您只创建了一个递归函数:

def send_data(self):
    self.send_data()
这会无休止地调用自身,这就是为什么最终会出现递归深度异常

您的第二个示例实际上没有调用该方法:

这里唯一的区别是你忘了使用

所有这些都与抽象基类或继承无关。您没有将send_data函数标记为abstract,即使您这样做了,使用abstractmethod所做的只是在没有具体实现替换它的情况下创建类的实例


您不会因为在ABCMeta类上定义了方法而获得AttributeError。请注意,方法只是类上的属性;它们不是独立的名称空间。self.send_数据引用绑定方法,而不是其他独立的属性。引用该方法而不调用它不会有任何其他作用。

我不确定您为什么希望得到一个属性错误。您有一个属性send_data;Base.send_data方法是一个属性。@vKohli:不,它不会,因为instance.send_data将找到重写的实现,而不是父类上的实现。@vKohli:self只是对实例的另一个引用。应用常规属性查找规则;首先查看实例属性,然后按MRO顺序查看类。因此,如果实例上不存在send_数据,则会找到Child.send_数据。Base.send\u数据是否存在并不重要。如果没有Child.send_数据,则会找到Base.send_数据。在一个方法中,self仍然是同一个实例,因此在Base.send_data中,引用self.send_data再次找到完全相同的方法。非常感谢您的解释比我问的问题要好得多。我是python的新手,现在我知道child.send_数据将在MRO订单之前提交。我还有一个疑问,self.send_data指的是方法send_data,它没有被调用,只是为了确保它仍然不是一个新属性?@vKohli:它不是一个新属性;self.send_数据只是对该方法的引用;您可以将其存储在变量中,然后再调用它。谢谢您的解释。
def send_data(self):
    self.send_data