Python怎样用C实现对象的多态性

        在Python中,一切皆为对象,所有的对象都有一些相同的内容,在PyObject中定义。

        //xk> 怎样实现继承

        PyObject是Python中一切(new style)类的基类,其定义非常简单

//xk> Python3.2.2_Source/Include/Object.h
typedef struct _object {
    _PyObejct_HEAD_EXTRA
    Py_ssize_t ob_refcnt; //xk> reference count
    struct _typeobject *ob_type; //xk> object的类型用type object来表示
} PyObject;
_PyObejct_HEAD_EXTRA宏不用管,在发布版Python中没有编译。PyObject结构体中仅仅定义了引用计数和类型信息。对象的类型也是对象(typedef _typeobject{...}PyTypeObject;),用类型对象来表示类型信息。

        怎么用C语言实现继承关系呢?子类继承了父类的内容,并有所增改,所以在内存布局上,只要把父类的内容放在对象的头部,就可以用父类指针指向子类对象。在Python内部,每个对象都有相同的对象头部——PyObejct的内容,这就使得在Python内部,对对象的引用变得非常统一,只需要用一个PyObject *指针就可以引用任意的对象。这对于实现多态是必要的。

        //xk> 怎样表示类型

        对象的类型定义了对象的数据成员和能够施加在对象之上的操作。查看Python3.2.2_Source/Include/Object.h中对_typeobejct的定义(内容非常多,不能在这里全部帖出来),包含了大量的函数指针。这些函数指针即表示该类型所定义的操作,亦即表示该类型的对象在运行时所表现的行为。

        在这些操作信息中,有三个指针比较重要:tp_as_number, tp_as_sequence, tp_as_mapping。以tp_as_number为例,它是PyNumberMethonds *指针,而PyNumberMethonds结构体定义了作为一个数值对象应该支持的操作。类似的,tp_as_sequence表示作为一个序列对象所支持的操作;tp_as_mapping表示作为一个关联对象所支持的操作。可见:在Python中,一个对象可以同时是数值对象、序列对象、关联对象,关键看它支持哪些操作,也就是定义了哪些非NULL的函数指针。因此,Python对象的多态性是基于行为的,而不像C++/Java等语言中多态性是基于类型的。Python对象实际上是全类型的,可以有的函数指针全部都有,只不过很多函数指针都是NULL,只要你实现了该函数,python对象就能表现出该行为。

>>> class MyInt(int):
            def __getitem__(self, key):
                return key + str(self)

>>> a = MyInt(1)
>>> b = MyInt(2)
>>> print a + b
3
>>> a['key']
'key1'
定义了一个子类从内建的int类继承而来,应该是数值对象,但是因为通过定义__getitem__方法,将MyInt在Python内部对应的PyTypeObejct对象中原本为NULL的函数指针重新赋值,使得该类型的对象能够表现出关联对象的特性。

        //xk> Python对象的多态性

        通过PyObject和PyTypeObejct,Python利用C语言实现了类似C++所提供的对象多态性(但是有所不同)。在Python中创建一个对象比如PyIntObject对象时,Python内部是用PyObject *指针而不是PyIntObject *指针来保存和维护这个对象,在Python内部各个函数之间传递的都是一种泛型指针——PyObject *,因此无法根据指针类型判断所指的对象究竟是个什么类型,只能从指针所指对象的ob_type域动态地进行判断。由此,Python实现了多态机制。

        //xk> 乱弹:C哲学和C++哲学的比较

        C哲学:保持简单。

        C++哲学:用复杂的工具对付复杂的现实问题,以此获取解决方案的简单直接。

        C和C++都意识到程序设计的本质问题是控制复杂度,只不过它们采用了不同的思路。

        C语言选择用分治法,模块化将一个复杂问题分解成许多相对简单的小问题,并精心设计模块之间的通信。这里的模块可以是一个函数、一个进程甚至一个独立的程序。Unix工具链哲学与此一脉相承。

        《C++沉思录》中阐明:类似汽车制造等传统工业,一方面用户接口越来越简单,另一方面内部实现越来越复杂。我们生活在一个如此复杂的世界里,因此Java和C#也不可避免地变得越来越复杂。C++的复杂源于要解决的现实问题的复杂。

        从理论上争论孰优孰劣是毫无意义的,两者都很有道理。C语言的选择有一定的问题,从整体来看模块化的设计容易导致多余(Python的每个对象都要定义对所有类型的操作的支持,大量的函数指针被设置为NULL),用C来实现面向对象的机制明显不如C++简单直接。虽然如此,C语言貌似要比C++受到更广泛的支持。C++貌似真的过于复杂了,既难于学习,开发效率又低。在面对非常非常复杂的问题时,从整体上来把握对操刀者提出了很高的要求,分而治之虽然难免冗余,好歹能够可行。

        最后说一句,对学生来说,选择哪个都没有错,饿死于干草堆之间才是最大的愚蠢。学习尽量与手头上的项目结合,把手上看似平淡无奇的事情做得比别人深入一步,learn by doing it.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值