类在python中以class定义。

 

从有道翻译可以看到,class中的阶级,班级或者等级也好,实则都是指一个群体。所以class用到python的语法中来就被称为‘类’,指一类事物的总称。

下面关于类的介绍可能不是很浅显,但尽量用易懂的话描述。

python中,类(class)中封装了一组相关数据(一般是一些方法和属性)。使之成为一个整体。

在用户(使用类完成一定功能的人)看来,类就是一个封装好了直接可用的工具,‘类’就好比是一辆汽车,用户只要知道怎么用油门、刹车、方向盘驾驶就好而不必去理会汽车中的零部件是如何工作的。

 

类与函数的异同(此处讲的函数与方法不是一个概念,不要混为一谈):

函数和类都是一种小粒度复用单位,但类的行为特征更复杂。

函数具有单一入口和出口,可以完成一次计算过程。而类从构造开始就面临多个方法,这些方法在不同的调用次序下会产生不同的结果。这也印证了类的行为特征更复杂。

 

类擅长对有持续状态、有生命周期、有遗传特性的物体进行抽象模拟。在保留物体共性的前提下,每个个体又会有自己的特征。如此一来,类关注数据本身(面向对象)。

类存在两种关系:1、继承自某个(某几个)族类;2、组合了哪些部件(方法、属性)

 

类与模块的异同:

类和生成多个实例;

类可被继承和扩展;

类实例的生命周期可控;

类支持运算符,可按需重载。

模块的粒度大,其可用来提供游戏场景级别的解决方案,而类则是该场景下特定家族和演员(模块>=类)

 

一、类的创建

 

以上的两种方式略有不同,这里加不加括号在python3中已无影响,因为python3已做优化。

实则都是继承于object的。

 

关键字class是运行期的指令。完成对类型对象的创建。并且类可以在函数内部定义。而非我们常见的在类中定义‘函数’,这里类中的函数我更愿意称其为‘方法’。

 

类在函数test中被定义。

反汇编查看具体创建过程

 

反汇编:在执行python代码的过程中是python代码先被编译为字节码后,再由python虚拟机执行字节码。Python的字节码其实是一种类似于汇编指令的中间语言,一条python语句会对应若干条字节码指令。然后虚拟机一条一条执行字节码指令,从而完成程序执行。

dis模块支持对python代码进行反汇编,成为字节码,从而能够清楚python代码背后的执行过程。

由上述执行结果为例

第一列的数字表示对应源代码的行数(这里第一列的数字是2)。

第二列的数字是字节码的索引,指令LOAD_BUILD_CLASS0的位置。

第三列是指令执行的功能描述,也是我们可读的

第四列是指令的参数

第五列是计算后的实际参数

从反汇编结果来看,先创建X函数,然后是属性(data)设置和方法(get())创建.随后这个X函数被当作参数传递给builtins.__build_class__调用.__build_class__调用X.会提供一个字典作为堆栈帧的名字空间.用于保存类型成员,完成后将字典连同名字和基类一起传递给元类,最终生成目标类型的对象.(元类用于创建类型对象)

 

Python在编码过程中会生成codeObject(如上述第一张反汇编图中的<code object X>), CodeObject是在虚拟机中的抽象表示。

二、类与实例

  类在模块中定义,类的生命周期与模块等同。如果其被放在函数内,那么每次都是新建。即使每次都是相同的名字和内容,也属于不用的类了。

 

若在函数内定义类,那么在所有实例死亡后,会被回收。

类型对象除了用来创建实例外,也为所有实例定义了操作接口,类型负责管理整个家族的可共享数据和行为模板。实例仅保留私有特征,其以内部引用从 所属的类型和祖先类型 中查找到需要的方法。用来展现个体的面貌。

 

类型创建的众多实例中,实例之间并无直接关系,单个实例从诞生到消亡整个过程都不影响类型或者其他实例。

三、类的名字空间

  类型有自己的名字空间,里面存储的是当前类型定义的方法和字段。类的祖先类型的成员并不在此列,祖先的类型成员还是由引用关联。

class A:
    a  =10   # 类字段

    def __init__(self, x):     # 实例初始化方法
        self.x = x    # 实力字段

    def get_x(self):  # 实例方法
        return self.x

class B(A):   # 继承A  
    b = "python"

    def __init__(self, x, y):
        super().__init__(x) # 引用父类A的初始化方法
        self.y = y

    def get_y(self):
        return self.y
>>> ad = B(1,2)  # 实例化


实例会存储所有继承层次的实例字段(上面的ad会继承A、B的实例字段),因为这些都是属于ad自己的的私有数据(类共有的数据都存放在__init__( )方法中)

>>> A.__dict__
mappingproxy({'__module__': '__main__', 'a': 10, '__init__': <function A.__init__ at 0x00000000005E1EA0>, 'get_x': <function A.get_x at 0x0000000003136840>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
>>> B.__dict__
mappingproxy({'__module__': '__main__', 'b': 'python', '__init__': <function B.__init__ at 0x00000000031368C8>, 'get_y': <function B.get_y at 0x0000000003136950>, '__doc__': None})

类型的名字空间返回 mappingproxy只读视图 不允许直接修改

>>> ad = B(1,2)
>>> ad.__dict__
{'x': 1, 'y': 2}
>>> dir(ad)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'get_x', 'get_y', 'x', 'y']
>>> ad = B(1,2)
>>> ad.__dict__
{'x': 1, 'y': 2}
>>> dir(ad)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', 
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', 
'__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
 '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'get_x', 
'get_y', 'x', 'y']

而实例的名字空间是普通字典,可以直接修改。函数dir返回所有可访问的成员名字。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值