Python是一种非常机动的编程语言,它的机动性很大程度上来自于它的对象系统。
在Python中,一切都是对象,这意味着无论是数字、字符串,还是我们自己定义的类的实例,它们在底层都遵循雷同的规则。
本文尝试揭开Python的对象系统的神秘面纱。
1. 对象和范例
在Python中,每个对象都有一个范例(type),而范例本身也是一个对象。
比方,int是整数的范例,str是字符串的范例,而我们自己定义的类(class)也是一种范例。
1.1. 对象 PyObject
在CPython中,所有对象都基于一个底层的结构体PyObject。
这个结构体定义了每个对象的基本属性,比如它的引用计数(用于垃圾回收)和它的范例指针。
PyObject的定义在源码中:Include/object.h中。- // _object 就是 PyObject 的别名
- typedef struct _object { };
复制代码 当我们创建一个整数对象时,它现实上是一个PyLongObject,它扩展了PyObject结构体:- // _longobject 是 PyLongObject 的别名
- struct _longobject {
- PyObject_HEAD
- _PyLongValue long_value;
- };
复制代码 _longobject定义在源码文件:Include/cpython/longintrepr.h中。
Python代码中,我们可以通过type()函数查看一个对象的范例:- a = 42
- print(type(a)) # <class 'int'>
- s = "hello"
- print(type(s)) # <class 'str'>
复制代码 1.2. 范例 PyTypeObject
范例(PyTypeObject)定义了对象的行为。
它的定义在源码:Doc/includes/typestruct.h文件中。
它的定义中包罗了许多函数指针,这些函数指针决定了对象如何相应某些操纵。
比方,tp_str函数指针定义了对象如何转换为字符串,
tp_as_number函数指针中则定义了加减乘除等等数值计算操纵。- typedef struct _typeobject {
- PyObject_VAR_HEAD
- const char *tp_name; /* For printing, in format "<module>.<name>" */
-
- /* Method suites for standard classes */
- PyNumberMethods *tp_as_number;
- reprfunc tp_str;
- // 省略... ...
- } PyTypeObject;
复制代码 其中的PyNumberMethods在Include/cpython/object.h中有定义。
包罗了各种数值计算的函数指针。- typedef struct {
- /* Number implementations must check *both*
- arguments for proper type and implement the necessary conversions
- in the slot functions themselves. */
- binaryfunc nb_add;
- binaryfunc nb_subtract;
- binaryfunc nb_multiply;
- // 省略... ...
-
- } PyNumberMethods;
复制代码 也就是说,当一个类实现了这些函数指针,那么它的对象就能执行这些操纵。
2. 类的特殊方法
在Python中,我们经常利用特殊方法(如 __add__ 、 __str__ 等)来定义对象的行为。
现实上,这些特殊方法与上面介绍的函数指针是相互关联的。
比如,类的__add__ 方法与上一节中PyTypeObject中的PyNumberMethods中的nb_add相对应,
而__str__则与上面的tp_str相对应。
只要类实现了这些特殊方法(比如,__add__和__str__),那么,PyTypeObject中对应的函数指针就指向这些特殊方法的实现。
根据这个类创建的对象就有了相应的功能。
下面通过简单的例子来看看这个函数指针的作用。
首先,我们创建一个类,先不实现__add__和__str__。- class MyClass:
- def __init__(self, n):
- self.n = n
复制代码 然后根据这个类创建一个对象,并进行加法运算:- if __name__ == "__main__":
- obj = MyClass(10)
- obj + 1
复制代码 运行结果:
果然,因为PyTypeObject中PyNumberMethods字段中的nb_add对应的函数指针没有实现,无法进行加法运算。
修改MyClass类,实现__add__方法。- class MyClass:
- def __init__(self, n):
- self.n = n def __add__(self, m): self.n += mif __name__ == "__main__":
- obj = MyClass(10)
- obj + 1 print(obj)
复制代码
这时,MyClass的对象可以正常进行加法运算了,但是print出来的结果是对象的内存地址,我们希望看到对象中n的值。
再次修改MyClass,实现__str__方法,也就是对应PyTypeObject中tp_str对应的函数指针。- class MyClass:
- def __init__(self, n):
- self.n = n def __add__(self, m): self.n += m def __str__(self): return f"当前值: {self.n}"
复制代码
这样,MyClass的对象既可以进行加法运算,也可以输出可读性较好的内容。
再补充一点,子类继承父类时,会主动继承父类中已经实现的特殊方法,比如:- class MyInt(int):
- pass
- a = MyInt(10)
- b = MyInt(20)
- print(a + b) # 输出: 30
复制代码 MyInt继承了int范例的nb_add和tp_str。
3. 范例的创建
在Python中,我们可以通过两种方式创建范例:静态定义和动态分配。
3.1. 静态定义
Python的内置范例(如int、float)是通过静态定义的方式创建的。
它们的特殊方法直接指向详细的实现函数。
int和float定义的源码分别在:Include/longobject.h和Include/floatobject.h。
3.2. 动态分配
我们自己定义的类是通过动态分配的方式创建的。
当我们利用class语句定义一个类时,Python会主动为我们设置好所有须要的特殊方法。
比方:- class MyClass:
- def __str__(self):
- return "Hello from __str__!"
- obj = MyClass()
- print(obj) # 输出: Hello from __str__!
复制代码 在这个例子中,MyClass的tp_str函数指针被设置为一个函数,这个函数会调用我们的 _str__方法。
4. self和方法
在Python类的定义中,方法是一种特殊的属性。
当我们通过实例调用方法时,Python会主动将实例作为第一个参数通报给方法。- class MyClass:
- def my_method(self):
- return "Hello from my_method!"
- obj = MyClass()
- print(obj.my_method()) # 输出: Hello from my_method!
复制代码 上面的例子中,my_method是一个函数,但它通过形貌符协议酿成了一个方法。
当我们通过obj.my_method()调用它时,self参数会主动被设置为obj。
这里面提到的形貌符协议是Python中一个非常强大的机制,它允许对象控制对属性的访问(如获取、设置和删除)。
形貌符是Python中实现属性访问控制的基础,也是许多高级功能(如property、classmethod、staticmethod等)的底层实现原理。
形貌符本质上就是一个包罗以下方法的类:
- __get__(self, instance, owner):用于访问属性时调用,instance是访问属性的实例,owner是该实例所属的类
- __set__(self, instance, value):用于设置属性时调用
- __delete__(self, instance):用于删除属性时调用
根据形貌符协议,当通过对象(obj)访问my_method时,返回的是一个绑定方法,它会主动将实例对象作为self参数,这种行为是由__get__方法实现的。
5. 总结
Python对象系统的核心是PyObject和PyTypeObject。
每个对象都有一个范例,而范例定义了对象的行为,特殊方法与CPython中的函数指针之间存在直接的映射关系。
Python会根据我们定义的特殊方法主动设置函数指针,同时,特殊方法也可以从父类继承。
通过理解这些概念,我们可以更好地理解Python的动态特性和机动性。当我们利用class定义一个类时,可以想想背后发生的故事。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |