一个类的主要价值在面向对象编程中是发挥抽象的作用。在 Python 中每一个数据类型都是某个类的实例。一个类提供了许多行为,每个行为也就是其中的方法,也就是定义成类的实例方法。
一个类也起到了作为自身实例的一种蓝图作用。这样对于一个类的每个实例来说,都能有效地确定状态信息,常会称为属性,有时也会叫做财产项。例如,实例变量,数据。
定义一个类如同定义函数似的,使用 class 语句,但是有几点特殊地方需要重新认识一下:
第一 self 识别符:
在 Python 中定义任何一个实例方法时,第一位置参数名使用了默认的 self 作为惯例。那么 self 这个参数扮演了一个重要的、关键的角色。那就是 self 会识别实例会使用哪一个方法。例如:
class C(object):
def __init__(self):
pass
def get(self):
pass
假设我们有一个 C 类,那么 a 和 b 分别是 C 的一个实例,当 a.get()的时候,或 b.get()的时候,C 类会知道是 a 调用了.get()方法还是 b 调用了.get()方法。这就是 self 参数的作用。
由于有了 self 这个关键作用,那么类的众多实例都只会维护着自己的状态信息。解释器会自动地把与实例牵扯在一起的方法绑定到 self 参数上,不会出现认错对象的现象。
第二构造器:
当建立一个类的实例时,例如 a = C()那么圆括号对儿的作用就是启动构造器开始建立类 C 的一个实例,并分配给变量 a 这个对象。构造器的作用就是调用类 C 做事情。
第三初始化:
当建立一个类的实例时,例如 b = C('name')那么圆括号对儿中的参数值会代入到类中的一个名叫 dunder init 实例方法中,这种使用类时提供参数值的用法是由类的实例初始化方法决定的。这与定义函数时有所不同,调用函数时直接把参数名描述在构造器中即可,而类在建立实例时要想使用参数的话,就要在类里写一个 dunder init 实例方法来决定调用类时的初始情况。例如:
class C(object):
def __init__(self, name):
self.name = name
这样的一个类定义完,使用时就只能用作 b = C('name')这种写法。参数 name 的值会分配给实例变量 self.name 这里要注意,右边的 name 参数名是位于本地范围中。
第四封装:
前面提到过命名前使用单个下划线时,会默认作为非公开名。那么实例不能直接使用这类数据。例如:
class C(object):
def __init__(self, name):
self._name = name
def get(self):
return self._name
作为一种通用规则,我们会把所有数据对象处理成非公开形式。这样能够让我们更好的保持所有实例的状态一致性。那么如果我们想要让实例访问这样的数据时,可以定义实例方法来发挥只读数据的行为,或者更新数据的行为。在这种数据结构中,封装内部的表现形式可以增加类的灵活性,可以对类的结构进行重新设计,提升效率。
第五检查错误:
对于例子中的数据类型我们没有做检查步骤,一般来说,名字的内容都应该是字符串类型,那么如果建立实例时使用了其它数据类型的话,虽然可以建立成功,但不是我们所期望的数据类型。如果在数据上进行操作的话,甚至会出现抛出例外错误的情况。
第六检测类:
前面提到过单元测试,最后我们会在 if __name__=='__main__':这个执行区域里去写一些对定义的类的测试代码。
类的定义基本上包含的注意事项就是以上六点,并不是直接写一个类就完成了定义类的工作。