CPython解释器如何处理面向对象编程(OOP)?

3

最近一个朋友问道:“CPython解释器实际上如何处理面向对象编程(OOP)?”

这个问题让我感到困惑,因为我知道C语言并不是一种面向对象的语言。

我尝试着谷歌搜索StackOverflow以及阅读CPython Wiki,但是我没有找到有用的信息。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def getInfo(self):
        return "Name: " + self.name + "\nAge: " + str(self.age)

# How the heck does CPython handle this?
personOne = Person("Bob", 34)
personTwo = Person("Rob", 26)

print( personOne.getInfo() )
print( personTwo.getInfo() )

所以现在我真的想知道!CPython解释器如何处理像对象这样的东西,如果它本身不是面向对象的?
2个回答

6

这里有一个小的思考实验:你的CPU根本不是“面向对象”的。相反,它只能执行像“将寄存器1加到寄存器2并将结果放入寄存器3”和“如果寄存器5大于零,则执行此goto语句”这样的指令。但一些Python等面向对象语言还是可以在CPU上运行。如何实现的呢?


6
Python的面向对象编程实现的完整复杂性远超出了Stack Overflow回答的范围,但是可以提供一个概述。这将忽略很多细节,例如元类、多重继承、描述符和C级API。尽管如此,它应该让你感到为什么实现这样的东西是可能的,并且对如何完成它有一个总体印象。如果您想了解全部细节,您应该浏览CPython源代码
一个像你的Person类实例的对象包括以下内容:
  • 一个类
  • 一个持有其属性的字典
  • 其他一些目前不相关的东西,比如__weakref__
一个类也很简单。它有:
  • 一个基类
  • 一个持有其属性的字典
  • 其他一些目前不相关的东西,比如类名。

当您使用class语句定义一个类时,Python会将指向您选择的基类(如果您没有选择,则为object)的指针和保存您定义的方法的字典捆绑在一起,这就是您的新类对象。它有点像以下元组。
Person = (object,
          {'__init__': <that __init__ method you wrote>,
           'getInfo': <that getInfo method you wrote>},
          those irrelevant bits we're glossing over)

但不是元组。在C级别,这个记录几乎是作为结构体实现的,但并非完全相同。


当你创建一个类的实例时,Python会将指向你的类的指针和一个新字典捆绑在一起作为实例的属性,并且这就是你的实例。这有点像下面的元组:
personOne = (Person, {}, those irrelevant bits we're glossing over)

但是,它不是一个元组。在C级别上,它几乎实现为结构体,但并非完全如此。

然后它运行__init__,将新实例和您提供给类的其他参数传递给__init__

Person.__init__(personOne, "Bob", 34)

属性赋值被翻译为在对象的字典中设置条目,因此在__init__中的赋值操作如下:
def __init__(self, name, age):
    self.name = name
    self.age = age

导致字典最终处于以下状态:
{'name': 'Bob', 'age': 34}

当你调用personOne.getInfo()时,Python会先查找personOne的字典,然后是它所属类的字典,再然后是它的超类的字典等等,直到找到'getInfo'键的条目。相关联的值将是getInfo方法。如果该方法在类字典中找到,Python将把personOne插入为第一个参数。(它如何知道插入该参数的详细信息在描述符协议中。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接