共4613字,阅读需要12分钟
一 定义
类 (class) 封装一组相关数据,使之成为一个整体,并使用一种方法持续展示和维护。这有点像把零件组装成整车提供给用户,无须了解汽车的内部结构和工作原理,只要知道方向盘,刹车和油门这些外部接口就可以正常行驶。类存在两种关系1、继承(inheritance,is-a)自某个族类继承可以用来表达本车属于某厂的哪个车族系列,除了继承原车系的技术和优势,还可基于某些环境进行改进。2、组合(composition,has-a)了哪些部件组合可用来表述该车使用了哪些零部件,比如最新的发动机。类与模块的不同之处1、类可生成多个实例。2、类可被继承和扩展。3、类实例的生命周期可控。4、类支持运算符,可按需重载。这些特性模块没有或者不需要,同时,模块粒度大,模块可用来提供游戏场景级别的解决方案,而类则是该场景下的特定家族和演员。1.2、创建定义类,以此为个体为例。关键字 class 同样是运行期指令,用于完成类型对象的创建。
可在函数内定义,以限制其作用范围。类型与实例如果类在模块中定义,那么其生命周期与模块等同,如果被放在函数内,那么每次都是新建。即便名字和内容相同,也属于不同类型。
函数内定义的类型对象,在所有实例死亡后,会被垃圾回收。类型对象除了用来创建实例,也为所有实例定义了基本操作接口,其负责管理整个家族的可共享数据和行为目标。实例只保存私有特征,其以内部引用从所属类型或其它所属祖先类查找所需的方法,用来驱动展现个体面貌。
名字空间
类型有自己的名字空间,存储当前类型定义的字段和方法。这其中并不包括所继承的祖先成员,其同样以引用关联祖先类型,无须复制到本地。
实例 instance o 会保存所有继承层次的实例字段,因为这些都属于其私有数据。
当通过实例或类访问某个成员时,会从当前对象开始(instance o 开始查找),依次由近到远向祖先类查找(即 o --> class B --> class A 进行成员查找)。如此做的好处就是祖先类的新增功能可以直接 【广播】给所有后代。在继承层次的不同名字空间中允许有同名成员,并按顺序优先命中。
二 字段
依照所处空间不同,我们将字段分为类型字段和实例字段。官方将成员统称为 Attribute,我们可按例将数据当做字段。2.1、类型字段【类型字段】在 class 语句块内直接定义,而实例字段必须通过实例引用(self)赋值定义。仅从执行方式来看,无论实例方法存在于哪级类型,其隐式参数 self 总指向当前调用实例。
实例参数 self 只是约定成俗的名字,这类似于其它语言中的 this,换成 this 同样有效。2.2、字段赋值可使用赋值语句为类型或实例添加的新字段。
可一旦实例重新赋值,就将会在其名字空间建立同名字段,并会遮蔽原字段。
2.3、私有字段将私有字段暴露给用户是很危险的。因为无论是修改还是删除都无法截获,由此可能引发意外错误。因为语言没有严格意义上的访问权限设置,所以只好将它们隐藏起来。如果成员名字以双下划线开头,但没有以双下划线结尾,那么编译器会自动对其重命名。
同时双下划线开头课结尾的,通常是系统方法,比如 __ init __ ,__ hash __ ,__ main __等。所谓重命名,就是编译器附加了类型名称前缀。虽然这种做法不能真正阻止用户访问,但基于名字的约定也算一种提示。这种方式让继承类也无法访问。重命名机制总是针对当前类型,继承类型无法访问重命名后的基类成员。可将双下划线前缀改为单下划线,这样虽然不能自动重命名,不过提示作用依旧。
三 属性
对私有字段会进行重命名保护,那公开字段如何处理呢?
问题是核心在于访问拦截,必须由内部逻辑决定如何返回结果。而属性(property)机制就是将读、写和删除操作映射到指定的方法调用上,从而实现操作控制。
这种 @ 语法被称作装饰器(decorator)。多个方法名必须相同,默认从读方法尅是定义属性,随后以属性名定义写和删除。如果实现只读,或禁止删除,则只需去掉对应的方法即可。
四、方法
方法是一种特殊函数,其与特定对象绑定,用来获取或修改对象状态。实际上,无论是对象构造,初始化,析构还是运算符,都以方法实现。根据绑定目标和调用方法的不同,方法可分为实例方法,类型方法,以及静态方法。名字以上下划线开始和结束的方法,通常有特殊用途,其由解释器和内部机制调用。实例方法实例方法与实例对象绑定,在其参数列表中,将绑定对象作为第一参数,以便在方法中读取或修改数据状态。在以实例引用调用方法时,无须显式传入第一实参,而由解释器自动完成。官方建议参数名用self,同样以 cls 作为类型方法的第一参数名。
类型方法类型方法用来维护类型状态,面向族群提供服务接口。除绑定的第一参数名称不同外,还需添加专门的装饰器,以便解释器将其实例方法区分开来。
静态方法静态方法,则更像是普通函数。其既不接收实例引用,也不参与类型处理,所以就没有自动传入第一参数。使用静态方法,更多原因是将类型作为一个作用域,或者当前类型添加便捷接口。
特殊方法下面又解释器自动调用,与对象生命周期相关的方法。
__ new __:构造方法,创建对象实例
__ init __:初始化方法,设置实例的相关属性
__ del __:析构方法,实例被回收时调用
创建实例时,会先调用析构方法和初始化方法。
如果 __ new __ 返回实例与 cls 类型不符,将导致 __ init __ 无法执行。
五 总结
学习到此,我总算把类的创建,属性和方法等弄清楚了,我最想强调一点,希望读者把 实例 self 参数弄明白,后续编码过程中使用较多。还要清楚实例方法和静态方法的区别。下一节将详细介绍类的继承及重载。
PS:文章中有你没掌握的吗?留言告诉我!
END
如果觉得我的文章对你有帮助,请告诉我!
领取专属 10元无门槛券
私享最新 技术干货