脚本语言的面向对象(一)类与类实例的关系

本文探讨Python与C++的面向对象编程差异,重点分析类与实例的关系、内存管理及方法调用机制,帮助理解Python类实例化的独特之处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

脚本语言诸如python,lua的面向对象与静态语言诸如C++的面向对象本质上有很大的区别。

拿python和C++举例,C++中定义了一个类class,例如:

class Obj
public:
    int data;
    void mem_func(){};

这里只是声明了一个类的,定义了类的属性和函数。在创建类的对象之前,也就是调用o = Obj()实例化一个对象之前,进程的内存中没有一个显式的变量来保存类的信息的。类的信息转化成代码段或数据段(有静态变量的情况下)写入了可执行文件中,然后被进程加载映射。等到实例化对象的时候才开始为对象实例分配应有的内存。

python定义一个类,例如:

class Obj:
    data = 'data'
    def cls_fun():
        pass
    def mem_fun(self):
        pass

实际上这段代码被加载时,就在内存里产生了一个对象,这个对象包含了Obj类的信息。也就是内存里有实实在在的对象指向Obj的,这一点与C++是完全不一样的。这里可以看作是在lua中定义了一个table,talbe中有属性字段和函数字段。

那么python类的实例与python类又是什么关系,产生的过程是怎么样的呢?

在我看来他们不是包含关系,也不是子类的关系,用lua的元表可以很好的解释。如果您不懂lua的元表,我可以再解释一遍。

我用粗糙一点的词语来概括,他们是索引关系。这个怎么讲?例如用o = Obj()生成了一个o对象实例,o和Obj在内存中是两个不同的对象,但是o可以索引到Obj对象(类对象,不是实例对象)。为了讲清楚这个概念,我引出另一个概念:作用域。每个对象有各自的作用域,Obj和o的作用域是不同的。Obj的作用域里面有data,cls_fun,mem_fun等字段,o刚开始的时候什么也没有。但是o作为Obj的实例,o是可以访问到Obj的作用域的,这也是类实例的特权之一。我们都知道,类实例既可以访问类实例变量,也可以访问类变量。例如o.data,其实是o先在他自己的作用域中查找,然后再在Obj的作用域查找。明白了这一点,你也能理解为什么类实例变量会隐藏类同名变量了。我想python内部也是这么实现,反正在我写lua语言解释器的时候是这么设计的。

按照这个思路,Obj的方法也只是在Obj的作用域中定义,而没有在o的作用域中定义。o能够调用到Obj的方法,例如o.mem_fun(),是因为先在o的作用域中查找,找不到mem_fun这个字段,然后才在Obj中查找的。方法调用的模式,也是要先转化的,o.mem_fun()其实是转化为了mem_fun(o)。这就是为什么类实例不能调用类方法的原因,例如o.cls_fun()要转化为cls_fun(o),但是cls_fun()是不需要参数,会报错的。

这样看来,其实也没有类方法和类实例方法之分,本质上都是类作用域的一个函数而已。调用类方法时,之所以要用Obj.cls_fun(),是因为要限定Obj这个作用域,因为其他类也可以有这个类方法名。然后类实例调用实例方法时,可以看作是这样的:Obj.mem_fun(o),Obj是他的作用域,o是函数的参数。搞清楚本质之后,理解类方法和类实例方法就非常简单了。记住,类和实例本身不拥有方法,只是方法在类的作用域而已,这点倒与C++的类静态函数和类成员函数的含义一致。

希望通过这篇,您能理解python中类与类实例的关系,这点是非常重要的,后面的继承,多重继承,多态,元类都是基于这个关系的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值