Python 面向对象备忘录
参考:https://liaoxuefeng.com/books/python/oop/index.html
1. 封装、继承、多态
略
2. self
成员方法和普通函数基本没有什么区别,可以使用默认参数、可变参数、关键字参数、命名关键字参数,唯一不同在于,第一个参数是实例变量 self。
在调用成员方法时,不需要显式地传入 self 参数。
3. 私有变量
默认成员变量是公有的,以双下划线开头的属性是私有变量,外部不能访问,需要通过 getter 和 setter 方法进行访问。
使用 getter 和 setter 方法进行访问的优势在于,可以在函数内进行参数检查,避免传入无效数值。
PS Python 解释器实际上将私有变量改成了 _类名__参数名 的形式,但是不推荐以这种方式访问私有变量。总之,Python 本身没有强制限制的机制,一切依靠自觉。
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))
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')
>>> bart = Student('Bart Simpson', 59)
>>> bart._Student__name
'Bart Simpson'
4. 特殊变量
以双下划线开头,并且以双下划线结尾的变量,是特殊变量,可以直接访问。注意与私有变量区分。
5. 鸭子类型
在静态语言中,若需要 Animal 类型,就只能接受 Animal 类型或其子类,否则无法调用特定的方法,比如 run() 方法;但对动态语言来说,只要传入的对象有对应的方法供调用即可,即 有 run() 方法的对象就可以视为 Animal 类。
这就是动态语言的“鸭子类型”,对继承的要求并不严格,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
实际案例:Scrapy 框架中的管道类型 (Pipaline)。我们编写自己的管道类型时,不需要指明继承的基类,只要实现了 process_item() 方法,就可以被框架自动使用。
6. 了解陌生对象的信息
| 函数 | 用法 |
|---|---|
type() |
type(a) 返回 a 的类型,a 可以是基本类型、类、函数、None |
isinstance() |
isinstance(h, Husky) 返回布尔类型,判断对象 h 是否为 Husky 类或其子孙类的对象;Husky 位置也可以传入元组,如 :isinstance(h, (list, tuple)),h 是其中一种类型,函数就返回 True |
dir() |
dir(a) 返回一个字符串 list,包含对象 a 全部的成员变量名和成员方法名 |
hasattr() |
hasattr(obj, 'x') 返回布尔类型,表示 obj 对象是否有 x 成员 |
getattr() |
getattr(obj, 'y',m) 返回 obj 对象的 y 成员,若不存在,返回 m |
setattr() |
setattr(obj, 'y', 19) 给 obj 对象设置 y 成员,值为 19 |
len() |
重写类的 __len__() 方法,即可对该类的对象使用 len() 函数 |
7. 实例属性与类属性
实例属性属于各个实例所有,互不干扰;
类属性属于类所有,所有实例共享一个属性;
类属性会被同名实例属性屏蔽。
8. 动态绑定实例成员
给实例添加类定义中没有的成员属性和成员方法
class Student(object):
pass
s = Student()
s.name = 'Michael'
可以使用 __slots__ 变量限制实例的属性
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
9. 简化 getter 和 setter
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
特别注意:属性的方法名不要和实例变量重名,否则会造成无限递归。
10. MixIn
Python 支持多继承。在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn。
目的在于,避免复杂的继承链,按需求组合不同类的功能,就可以构造出所需的子类。
11. 定制类
在类中实现特殊成员方法,可以定制类的功能。
| 方法 | 作用 |
|---|---|
__str__ |
返回打印类实例时的字符串 |
__repr__ |
返回程序开发者看到的字符串,类似于 __str__ |
__iter__ __next__ |
使实例可以用于 for ... in 循环 |
__getitem__ __setitem__ __delitem__ |
使实例可以按下标使用元素,如同 list。判断传入参数是否为切片对象后,可以实现切片方法。 |
__getattr__ |
动态返回一个属性 |
__call__ |
像调用函数一样对实例进行直接调用 |