面对对象编程
面向对象的设计思想是抽象出
Class
,根据Class
创建Instance
面向对象的抽象程度又比函数要高,因为一个
Class
既包含数据,又包含操作数据的方法Method
数据封装、继承和多态是面向对象的三大特点
class Student(object): def __init__(self, name, score): self.name = name self.score = score def print_score(self): print('%s: %s' % (self.name, self.score))
类和实例
- 面向对象最重要的概念就是类
Class
和实例Instance
- 类是抽象的模板
- 实例是根据类创建出来的一个个具体的
对象
- 定义类是通过
class
关键字class Student(object): pass
class
后面紧接着是类名,即Student
,类名通常是大写开头的单词,紧接着是(object)
,表示该类是从哪个类继承下来的,通常,如果没有合适的继承类,就使用object
类,这是所有类最终都会继承的类 - 创建实例是通过
类名 +()
实现的bart = Student()
- 通过方法
__init__
绑定一些属性def __init__(self, name, score): self.name = name self.score = score
- 创建实例的时候,必须传入与
__init__方法
匹配的参数,但 self 不需要传bart = Student('Bart Simpson', 59)
访问限制
- 属性名前加上
__
将属性编程私有变量,只有内部可以访问,外部不能访问有些时候会看到以一个下划线开头的实例变量名,比如
_name
,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,虽然我可以被访问,但是,请把我视为私有变量,不要随意访问
继承和多态
- 从某个现有的
class
继承,新的class
称为子类Subclass
,而被继承的class
称为基类、父类或超类Base class、Super class
,继承使子类获得了父类的全部功能 - 当子类和父类都存在相同的方法时,子类的方法覆盖了父类的方法,在代码运行的时候,总是会调用子类的方法。即:多态
- 在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行
获取对象信息
- 基本类型都可以用
type()
判断 class
类型使用isinstance()
判断
实例属性和类属性
- 实例和类都可以绑定属性
- 实例绑定的属性只有这个实例可以访问
- 类绑定的属性,所有实例都可以访问
- 如果实例与类绑定的属性名一样,类属性会将实例属性覆盖掉
>>> class Student(object): ... name = 'Student' ... >>> s = Student() # 创建实例 s >>> print(s.name) # 打印 name 属性,因为实例并没有 name 属性,所以会继续查找 class 的 name 属性 Student >>> print(Student.name) # 打印类的 name 属性 Student >>> s.name = 'Michael' # 给实例绑定 name 属性 >>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的 name 属性 Michael >>> print(Student.name) # 但是类属性并未消失,用 Student.name 仍然可以访问 Student >>> del s.name # 如果删除实例的 name 属性 >>> print(s.name) # 再次调用 s.name,由于实例的 name 属性没有找到,类的 name 属性就显示出来了 Student
面对对象高级编程
使用 __slots__
python
作为动态语言可以动态对实例或类添加属性或方法,为了限制这种特性,可以使用 __slots__
class Student(object):
__slots__ = ('name', 'age') # 用 tuple 定义允许绑定的属性名称
使用 __slots__
要注意, __slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:
>>> class GraduateStudent(Student):
... pass
...
>>> g = GraduateStudent()
>>> g.score = 9999
除非在子类中也定义 __slots__
,这样,子类实例允许定义的属性就是自身的 __slots__
加上父类的 __slots__
使用 @property
python
内置的 @property
装饰器把一个方法变成属性调用的:
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
可以定义只读属性
多重继承
在设计类的继承关系时,通常,主线都是单一继承下来的,例如, Ostrich
继承自 Bird
。但是,如果需要 混入
额外的功能,通过多重继承就可以实现,比如,让 Ostrich
除了继承自 Bird
外,再同时继承 Runnable
。这种设计通常称之为 MixIn
。
class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
pass
这样一来,我们不需要复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类。
定制类
枚举类
python
提供 Enum
来定义枚举类
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
value
属性则是自动赋给成员的 int
常量,默认从 1
开始计数
如果需要更精确地控制枚举类型,可以从 Enum
派生出自定义类:
from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun 的 value 被设定为 0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
@unique
装饰器可以帮助我们检查保证没有重复值