day19回顾:
运算符重载:
算术运算符: + - * / ...
比较运算符: < <= > >= == !=
位运算符: & | ^ ~ << >>
正负号: + -
in / not in __contains__
[] 索引和切片
迭代器
class xxx:
def __next__(self):
"在此处一定要实现迭代器协议"
...
可迭代对象:
class yyy:
def __iter__(self):
return 迭代器
with 语句
with 表达式1 [as 变量1], 表达式2 [as 变量2]:
....
环境管理器:
class xxx:
def __enter__(self):
...
def __exit__(self, 异常类型=None, 异常对象=None, 追踪=None)
day20笔记:
思考问题:
在学生管理的项目中,每个学生有三个属性: 姓名,年龄,成绩
class Student:
....
能否在不改变Student类的情况下,有最小改动的情况下,再添加一个属性: 家庭住址
面向对象开发 可以用继承/派生机制来实现添加新功能
继承(inheritance) 和 派生 (derived)
什么是继承/派生:
继承的目的是延续旧的类class 的功能
派生的目的是在旧类的基础上添加新的功能
作用:
可以将一些共有功能加在基类中,实现代码共享(代码重用)
在不改变超类的代码的基础上,改变原有的功能
继承/派生名词
基类(base class)/超类(super class)/父类(father class)
派生类(derived class)/子类(child class)
单继承的语法:
class 类名(超类名):
....
示例见 in:
练习:
定义一个类Car:
class Car:
def run(self, speed):
....
试改装车,让其有在水中运送的能力(不改变源Car类))
实现一个新类
class ShipCar:
def ship(self, what):
....
s = ShipCar()
s.run(100)
s.ship("石油")
继承 说明:
任何类都直接或间接的继承自object类
object类是一切类的超类 (祖类)
类的 __base__ 属性:
作用:
用来记录此类的基类
覆盖: override
什么是覆盖:
覆盖是指在有继承关系的类中,子类实现了与基类(超类)同名的方法,在子类实例调用该方法时,实际调用的是子类中的覆盖版本,这种现在叫覆盖.
示例见: override.py
问题?
当覆盖发生时,子类对象能否调用父类中方法呢???
super函数:
1. super(type, obj) 返回绑定超类的实例(要求obj必须为type类型的实例)
2. super() 返回绑定超类的实例,等同于super(__class__, self) 此函数必须在方法内调用
示例见: code
练习:
写一个自行车类Bicycle类,有run方法用来骑行,显示行走里程
class Bicycle:
def run(self ,....)
再写一个电动自行车类EBicycle 同样实现run方法.在run方法内显示里程和当前电量
class EBicyle(...):
def __init__(self, volume:"电量")
....
def run(self, ...)d
实现 当电动自行车没电时.调用父类的run方法
电量的设计自己完成
用于类的函数:
issubclass(cls, class_or_tuple) 判断一个类是否继承自其它的类,如果此类cls 是 class 或 tuple 中的一个派生子类,则返回True, 否则返回False
示例见: i
封装 enclosure
封装的目的是让使用者通过尽可能少的关心和使用变量名
类的封装是隐藏类的实现细结,让使用者不关心这些细节
Python 不能实现C++完全意义上的封装(是模似的封装)
私有实例变量和方法:
1. Python类中,以双下划线 (__) 开头,不以双下划线结尾的标识符为私有成员(实例变量或方法)
2. 私有实例变量和方法只能在类内使用,不能在类外使用
示例见:hidden_property.py
显式调用基类的构造方法
思考:
构造方法一定会被调用吗?
def __init__(self, ...): ...
当子类有自己的构造方法时,基类的构造方法将不会被自动调用
通常需要在子类的__init__ 构造 方法内显式调用基类的构造方法
多态 polymorphic:
什么是多态:
字面意思: "多种状态"
多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态
Python的全部对象都只有"运行时状态(动态)", 没有"C++/Java"里的"编译时状态(静态)"
面向对象的编程语言的特征:
继承 / 派生
封装(类和私有变量)
多态
多继承 multiple inheritance
多继承是指一个子类继承自两个或两个以上的基类:
多继承的语法:
class 类名(超类名1, 超类名2[, ...]):
...
示例见: cars.py
多继承的问题(缺陷)
标识符(名字空间) 冲突的问题
要谨慎使用多继承
示例见:multi_inherit_bug.py
PEP8编码规范:
代码编排:
1. 使用四个空格缩进, 不使用Tab,不允许使用Tab和空格混合
2. 每行最大长度79字节,超过的部分使用反斜杠折行
3. 类和全局函数的定义间隔两个空行,类内方法定义间隔一个空行,其它地方可以不加空行
文档编排:
1. import 部分,按标准,三方,自己定义顺序依次排序,之间空一行
2. 不要在一句import 中导入多个模块,如:不推荐import os, sys, time
3. 尽可能使用 import xxx 而不采用 from xxx import yy 引用库,因为可能出现名字冲突
空格的使用:
1. 各种右括号前不用加空格
2. 逗号,冒号,分号前不要加空格
3. 函数的左括号前不要加空格,如func(1)
4. 序列的左括号前不要加空格, 如lst[2]
5. 操作符左右各加一个空格,不要为了对齐增加空格
6. 函数默认参数使用赋值符左右省略空格
7. 不要将多条语句写在同一行, 尽管可以使用';' 分隔
8. if/for/while语句中,即使执行语句只有一句,也必须另起一行
注:避免不必要的空格
AutoPep8 快捷键
ctrl+shift+8 (Linux)
command + shift + 8(Mac OS X)
练习1:
实现两个文件的复制:
要求用 with 语句 打开和关闭文件
在复制文件时,要处理所有的异常状态