Python3中的简单方法继承

Python3中的简单方法继承,python,inheritance,Python,Inheritance,新手python继承问题。。当您编写以下内容时: class A: def foo(self): print("a") class B(A): pass b = B() getattr(b, "foo") 产生 <bound method A.foo of <__main__.B object at 0x000000000604CC88>> 看起来Python创建了一个绑定到A.foo的属性foo,它知道foo是一个A方法 我应

新手python继承问题。。当您编写以下内容时:

class A:
    def foo(self):
        print("a")

class B(A):
    pass

b = B()
getattr(b, "foo")
产生

<bound method A.foo of <__main__.B object at 0x000000000604CC88>>

看起来Python创建了一个绑定到
A.foo
的属性
foo
,它知道
foo
是一个
A
方法

我应该认为继承只是创建指向基类对象的指针(解释器知道它是基类对象)而不是在派生类中创建属性的副本吗


似乎这是一个重要的观点,但一开始我并不清楚-在玩
super()

的时候,我提出了这个问题。你部分正确,让我们从你的错误开始

我应该认为继承只是创建指向基类对象的指针吗

这是不正确的。当您使用
getattr(obj,attr)
或执行
obj.attr
访问属性时,Python首先通过。特别是,这意味着这不会发生在类创建时,而是发生在属性查找时

看起来Python创建了一个属性
foo
,该属性绑定到
A.foo

给你,你说得对。绑定类或实例方法会在过程中创建新对象

恢复属性后,Python可能需要绑定它。它首先检查它是否是一个对象,即一个具有
\uuuu get\uuuu
方法的对象,以允许将其绑定到某个实例

下面是
getattr
的Python实现,以帮助可视化检索属性时发生的情况

首先,这是Python如何使用mro解析类属性

然后,如果它是在Python中,这就是
getattr
的实现方式

def getattr(instance, attr):
    cls = instance if isinstance(instance, type) else type(instance)

    # Recover instance attribute
    if hasattr(instance, '__dict__') and attr in instance.__dict__:
        attr_value = instance.__dict__[attr]

    # Recover the attribute from the class
    else:
        attr_value = _resolve_cls_attr(cls, attr)

    # We recovered a simple class attribute
    if not hasattr(attr_value, '__get__'):
        return attr_value

    # We recovered an instance method from a class or a staticmethod descriptor
    if instance is cls or isinstance(attr_value, staticmethod):
        return attr_value.__get__(None, cls)

    # We recovered an instance method or a custom descriptor
    return attr_value.__get__(instance, cls)

记住,为了坚持你的问题,上面省略了几个步骤。举例来说,它不会像内置的
getattr
那样依赖
\uuuu getattr\uuuuu
\uuu getattribute\uuuuuu

当您使用
b.foo
时,Python将首先查看
b
\uu dict\uu
中找不到
foo的地方。然后,它将依次检查
mro()
,即类型层次结构中的所有类型,以检查它可以从何处获取
foo
。在你的例子中,它会先检查
B.foo
,然后再检查
A.foo
@poke right,所以我想我的问题的关键是:当你做
B(A)
foo
时,不会添加到
B
的命名空间中,相反,
\uuuuuu dict\uuuuu
包含所有在
B
中专门创建的属性,而不是从其他地方继承的属性,是吗?
\uuuuuu dict\uuuuuu
将只包含实例成员,即您执行
self.something=value
操作的对象。方法通常存在于类中,而不是实例中。@poke很高兴知道!所以说它是
foo
的正确方式不会添加到
B中。当你执行
B(A)
,而不是调用
B.foo
时,会检查
B.\uu dict\uu
,然后进一步检查MRO,因为找不到它?是的,任何属性访问都会像这样工作。这是一种非常容易误导人且有缺陷的处理描述符的方法。为什么要使用所有特殊的大小写,而不是只实现实际的规则(
\uuu get\uuuuuuuuuuuuuuuu(实例,cls)
对于一个实例,
\uuuuuu get\uuuuuuuuuuuuuuuuuu(无,cls)
对于一个类?另外,如果你要做描述符处理,数据描述符可能至少值得一提。@user2357112我是在凌晨1点左右写的,睡个好觉后可能会有所改善。请注意,答案中已经链接了文档到描述符。
def getattr(instance, attr):
    cls = instance if isinstance(instance, type) else type(instance)

    # Recover instance attribute
    if hasattr(instance, '__dict__') and attr in instance.__dict__:
        attr_value = instance.__dict__[attr]

    # Recover the attribute from the class
    else:
        attr_value = _resolve_cls_attr(cls, attr)

    # We recovered a simple class attribute
    if not hasattr(attr_value, '__get__'):
        return attr_value

    # We recovered an instance method from a class or a staticmethod descriptor
    if instance is cls or isinstance(attr_value, staticmethod):
        return attr_value.__get__(None, cls)

    # We recovered an instance method or a custom descriptor
    return attr_value.__get__(instance, cls)