关于python:CPython解释器如何处理OOP

How does the CPython Interpreter handle OOP

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

这个问题最终使我感到困惑,因为我了解C不是一种面向对象的语言。

我尝试使用Google搜索,搜索StackOverflow甚至阅读CPython Wiki。但是我找不到有用的东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def getInfo(self):
        return"Name:" + self.name +"\
Age:"
+ 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解释器本身不是面向对象的,那么它将如何处理诸如对象之类的东西呢?


Python OOP实现的全部复杂性远远超出了Stack Overflow答案的范围,但是可以提供概述。这将掩盖许多细节,例如元类,多重继承,描述符和C级API。尽管如此,它应该使您理解为什么可以实现这样的事情,以及对它的完成方式的总体印象。如果需要全部详细信息,则应浏览CPython源代码。

类似于Person类实例的对象由以下各项组成:

  • 一类
  • 保留其属性的字典
  • 目前不相关的其他内容,例如__weakref__

一个类也很简单。它有

  • 基类
  • 保留其属性的字典
  • 目前不相关的其他内容,例如类名。

当您使用class语句定义一个类时,Python会捆绑一个指向您选择的基类的指针(如果未选择,则为object)和一个保存您定义的方法的字典,那是您的新类对象。就像下面的元组

1
2
3
4
Person = (object,
          {'__init__': <that __init__ method you wrote>,
           'getInfo': <that getInfo method you wrote>},
          those irrelevant bits we're glossing over)

但不是元组。 (在C级别,此记录几乎但不是完全作为结构实现的。)

创建类的实例时,Python会将指向您的类的指针和该实例的属性的新字典捆绑在一起,这就是您的实例。有点像下面的元组:

1
personOne = (Person, {}, those irrelevant bits we're glossing over)

但同样,不是元组。同样,它几乎(但不是完全)实现为C级结构。

然后它运行__init__,并将新实例以及您提供给类的其他任何参数传递给__init__

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

属性分配被转换为对象字典中的设置项,因此__init__

中的分配

1
2
3
def __init__(self, name, age):
    self.name = name
    self.age = age

使字典最终处于以下状态:

1
{'name': 'Bob', 'age': 34}

当您调用personOne.getInfo()时,Python依次查找personOne \\的字典,其类的字典,其超类的字典等,直到找到'getInfo'的条目。钥匙。关联的值将是getInfo方法。如果在类dict中找到该方法,Python将插入personOne作为第一个参数。 (如何知道如何插入该参数的详细信息在描述符协议中。)


这是一个小小的思想实验:您的CPU根本不是"面向对象的"。相反,它只能执行"将寄存器1添加到寄存器2并将结果放入寄存器3"中的指令,并且"如果寄存器5大于零,则执行此goto语句。"然而CPU以某种方式可以运行Python和其他面向对象的语言。怎么样?