CPython 解释器如何处理 OOP
How does the CPython Interpreter handle OOP
最近有朋友问"How does the CPython Interpreter actually handle OOP (Object Orientated Programming)?"。
这个问题最终让我感到困惑,因为我知道 C 不是一种面向对象的语言。
我试过了Googling it, searching Whosebug and even reading the 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 解释器本身不是面向对象的,那么 CPython 解释器如何处理对象之类的东西?
这是一个小的思想实验:你的 CPU 根本不是 "object oriented"。相反,它只能执行 "add register 1 to register 2 and put the result in register 3" 和 "if register 5 is greater than zero, then execute this goto statement." 之类的指令,但不知何故 CPU 可以 运行 Python 和其他面向对象的语言。怎么样?
Python 的 OOP 实现的全部复杂性远远超出了 Stack Overflow 答案的范围,但可以提供一个概述。这将掩盖很多细节,例如元classes、多重继承、描述符和 C 级 API。不过,它应该让您了解为什么可以实现这样的事情,以及它是如何完成的一般印象。如果你想要完整的细节,你应该浏览 CPython source code.
像您的 Person
class 实例的对象包含以下内容:
- 一个class
- 保存其属性的字典
- 其他现在不相关的内容,例如
__weakref__
。
A class 也很简单。它有
- 一个基地class
- 保存其属性的字典
- 其他现在不相关的东西,比如 class 名字。
当您使用 class
语句定义 class 时,Python 会捆绑指向您选择的基数 class 的指针(或 object
如果你没有选择一个)和一个包含你定义的方法的字典,这就是你的新 class 对象。有点像下面的元组
Person = (object,
{'__init__': <that __init__ method you wrote>,
'getInfo': <that getInfo method you wrote>},
those irrelevant bits we're glossing over)
但不是元组。 (在 C 级别,此记录几乎(但不完全)作为结构实现。)
当您创建 class 的实例时,Python 将指向您的 class 的指针和实例属性的新字典捆绑在一起,这就是您的实例。它有点像下面的元组:
personOne = (Person, {}, those irrelevant bits we're glossing over)
但同样,不是元组。同样,它几乎(但不完全)作为 C 级别的结构实现。
然后它运行 __init__
,传递 __init__
新实例以及您提供给 class:
的任何其他参数
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
的字典,然后是 class 的字典,然后是它的 superclass' s dict 等,直到找到 'getInfo'
键的条目。关联值将是 getInfo
方法。如果在 class 字典中找到该方法,Python 将插入 personOne
作为第一个参数。 (它如何知道插入该参数的详细信息在 descriptor protocol 中。)
最近有朋友问"How does the CPython Interpreter actually handle OOP (Object Orientated Programming)?"。
这个问题最终让我感到困惑,因为我知道 C 不是一种面向对象的语言。
我试过了Googling it, searching Whosebug and even reading the 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 解释器本身不是面向对象的,那么 CPython 解释器如何处理对象之类的东西?
这是一个小的思想实验:你的 CPU 根本不是 "object oriented"。相反,它只能执行 "add register 1 to register 2 and put the result in register 3" 和 "if register 5 is greater than zero, then execute this goto statement." 之类的指令,但不知何故 CPU 可以 运行 Python 和其他面向对象的语言。怎么样?
Python 的 OOP 实现的全部复杂性远远超出了 Stack Overflow 答案的范围,但可以提供一个概述。这将掩盖很多细节,例如元classes、多重继承、描述符和 C 级 API。不过,它应该让您了解为什么可以实现这样的事情,以及它是如何完成的一般印象。如果你想要完整的细节,你应该浏览 CPython source code.
像您的 Person
class 实例的对象包含以下内容:
- 一个class
- 保存其属性的字典
- 其他现在不相关的内容,例如
__weakref__
。
A class 也很简单。它有
- 一个基地class
- 保存其属性的字典
- 其他现在不相关的东西,比如 class 名字。
当您使用 class
语句定义 class 时,Python 会捆绑指向您选择的基数 class 的指针(或 object
如果你没有选择一个)和一个包含你定义的方法的字典,这就是你的新 class 对象。有点像下面的元组
Person = (object,
{'__init__': <that __init__ method you wrote>,
'getInfo': <that getInfo method you wrote>},
those irrelevant bits we're glossing over)
但不是元组。 (在 C 级别,此记录几乎(但不完全)作为结构实现。)
当您创建 class 的实例时,Python 将指向您的 class 的指针和实例属性的新字典捆绑在一起,这就是您的实例。它有点像下面的元组:
personOne = (Person, {}, those irrelevant bits we're glossing over)
但同样,不是元组。同样,它几乎(但不完全)作为 C 级别的结构实现。
然后它运行 __init__
,传递 __init__
新实例以及您提供给 class:
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
的字典,然后是 class 的字典,然后是它的 superclass' s dict 等,直到找到 'getInfo'
键的条目。关联值将是 getInfo
方法。如果在 class 字典中找到该方法,Python 将插入 personOne
作为第一个参数。 (它如何知道插入该参数的详细信息在 descriptor protocol 中。)