2.1 面向对象与面向过程
面向过程:从机器角度出发考虑问题
面向对象:从人的角度出发考虑问题
比如:学生上学
面向过程
起床
洗刷刷,穿衣打扮
出门,往教室方向走
if 走到十字路口:
while 红灯亮:
等待绿灯
走到教室
while 上课时间未到:
等待上课
开始上课
while 下课时间未到:
等待下课
吃饭
睡觉
打豆豆
面向对象
定义一个学生类
定义学生类的属性:姓名、性别、年级、专业、班级、……
定义学生类的方法:吃饭()、睡觉()、上课()、下课()、……
定义一个教室类
定义教室类的属性:位置、容量、类别、……
定义教室类的方法:开门()、关门()、……
定义一个学生类的对象:张三
定义一个教室类的对象:bz201
张三.上课(bz201)
面向过程适合底层开发、快速开发
面向对象适合上层开发、组织大规模团队开发
2.2 什么是对象
天上飞的:飞机、大炮、鸟、鹰、……
地上跑的:鸡鸭鹅、狗猫人、猪牛羊、……
水里游的:鱼虾蟹、……
抽象的概念:作业、项目、工作、公式……
世界上万事万物都是对象
2.3 区分类和对象
思考:
1 狗是类 狗是对象
2 张三是类 张三是对象
结论:对象是具体的概念,具体的某个事物。类是抽象的概念,是多个个体的结合
一个类中可以包含多个对象
对象是类的特殊表现
因为是面向对象编程,所以是对实际的个体,比如张三李四进行编程
张三.xxx
李四.yyy
王五.zzz
2.4 Python中声明类和创建对象
声明类:使用关键字 class
编码规则:类名首字母必须大写
class 类名:
类的实现代码
比如:
# 声明一个狗类
class Dog:
pass
# 创建类的对象
dog1 = Dog()
print(dog1) # <__main__.Dog object at 0x000001B9BB3AF7F0>
print(type(dog1)) # <class '__main__.Dog'>
2.5 属性
属性是类中的特性
设置属性
# 声明一个狗类
class Dog:
pass
dog1 = Dog()
# 设置狗的属性
# 对象名.属性名 = 属性值
dog1.name = '旺财'
dog1.age = 8
dog1.sex = 'male'
# 读取狗的属性
# 对象名.属性名
print(dog1.name)
print(dog1.age)
print(dog1.sex)
如果想要查看对象或类的属性,可以通过 dir() 函数查看
dog1 = Dog()
print(dir(dog1)) # 没有 'age', 'name', 'sex'
# 设置狗的属性
# 对象名.属性名 = 属性值
dog1.name = '旺财'
dog1.age = 8
dog1.sex = 'male'
print(dir(dog1)) # 有 'age', 'name', 'sex'
# 读取狗的属性
# 对象名.属性名
print(dog1.name)
print(dog1.age)
print(dog1.sex)
发现,name、age、sex属性是临时添加上去的
如果希望属性固定在类中,可以把属性写到类的实现代码中
class Dog:
name = ''
age = 0
sex = 'male'
dog1 = Dog()
print(dir(dog1)) # 有 'age', 'name', 'sex'
dog2 = Dog()
print(dir(dog2)) # 有 'age', 'name', 'sex'
2.6 方法
方法是类中进行的一系列操作
定义方法:
class 类名:
...
def 方法名(方法参数列表):
方法体
[return 返回值]
方法的首字母必须小写。
与函数不同的是:函数可以独立存在,方法则必须依赖于类
方法的参数列表,首个参数必须是self
class Dog:
# 狗叫的方法
def bark(self):
print('旺')
dog1 = Dog()
dog1.bark()
方法可以传递参数
class Dog:
...
# 狗吃的方法
def eat(self, something):
print('狗吃' + something)
dog1 = Dog()
...
dog1.eat('骨头')
方法中访问类的属性,使用self
class Dog:
name = ''
...
# 设置狗的名字
def setName(self, name):
self.name = name
# 获取狗的名字
def getName(self):
return self.name
dog1 = Dog()
...
dog1.setName('小花')
print(dog1.getName())
2.7 __init__
__init__是Python自带的方法,表示初始化
当创建类的对象时,进行初始化操作,比如:网络连接、连接数据库、打开文件
当类的对象被创建的适合就会触发该方法的调用
class Dog:
# 初始化
def __init__(self, name, age):
self.name = name
self.age = age
dog1 = Dog('旺财', 8)
print(dog1.name)
print(dog1.age)
dog2 = Dog('小花', 12)
print(dog2.name)
print(dog2.age)
2.8 __del__
删除对象的适合清理用过的内容,两种情况会触发这个方法:
1 当程序退出的适合,系统清理对象,该方法会被调用
2 程序员主动调用 del 命令,主动触发该方法
class Dog:
# 初始化
def __init__(self, name, age):
self.name = name
self.age = age
# 退出
def __del__(self):
print('__del__')
self.name = ''
self.age = 0
dog1 = Dog('旺财', 8)
print(dog1.name)
print(dog1.age)
del dog1 # __del__
print('over')
2.9 封装
面向对象的三大特征:封装、继承、多态
封装是指把属性私有化(private)
Python中描述属性的私有化,通过前置下划线来表示
1 _xxx:单前置下划线(包外部不能访问)
2 __xxx:双前置下划线(其他类不能访问)
3 __xxx__:双前置双后缀下划线(类中自带的)
私有化后,类的外面无法直接获取该属性
一般需要通过 setXxx() 修改属性,通过 getXxx() 获取属性
class Dog:
def __init__(self, name, age):
self.__name = name
self.__age = age
def getAge(self):
return self.__age
def setAge(self, age):
if age > 0:
self.__age = age
# 创建对象
dog1 = Dog('旺财', 8)
dog1.setAge(-3)
print(dog1.getAge())
2.10 继承
子类继承父类
class 子类(父类):
子类的实现代码
父类中所有非私有的属性和方法,子类中都可以获取并使用
# 父类
class Animal:
def eat(self):
print('Animal eat')
# 子类
class Dog(Animal):
pass
#
dog1 = Dog()
dog1.eat()
print(dir(dog1))
子类中可以重写父类的方法
# 父类
class Animal:
def eat(self):
print('Animal eat')
# 子类
class Dog(Animal):
### 重写父类的方法 ###
def eat(self):
super().eat() # 调用父类的方法
print('Dog eat')
#
dog1 = Dog()
dog1.eat() # 调用子类的方法
print(dir(dog1))
子类还可以继续派生子类(孙类?)
# 子类的子类
class HabaDog(Dog):
### 重写父类的方法 ###
def eat(self):
super().eat() # 调用父类的方法
print('HabaDog eat')
#
dog2 = HabaDog()
dog2.eat()
如果一个类没有继承任何父类,则默认继承 object 类
下面两种写法等效
class Animal:
def eat(self):
print('Animal eat')
class Animal(object):
def eat(self):
print('Animal eat')
更推荐使用后者
2.11 多态
不同事物,对于同一个操作所表现出来的不同形态
外科医生、厨师、演员 cut...
动手术……切菜……下班
# 父类
class Animal:
def eat(self):
print('Animal eat')
# 子类
class Dog(Animal):
def eat(self):
print('Dog eat')
class Man(Animal):
def eat(self):
print('Man eat')
class Woman(Animal):
def eat(self):
print('Woman eat')
# 函数
def doEat(obj):
obj.eat()
#
dog1 = Dog()
man1 = Man()
woman1 = Woman()
doEat(dog1)
doEat(man1)
doEat(woman1)
doEat()方法中,理论上可以传递任意类型的对象
如果该对象中没有eat()方法,则会报错
考虑规定doEat()的参数必须是Animal或子类的对象
推荐使用 isinstance() 函数,判断对象是否为某个类的对象
a1 = Animal()
print(isinstance(dog1, Dog)) # True
print(isinstance(dog1, Animal)) # True
print(isinstance(a1, Animal)) # True
print(isinstance(a1, Dog)) # False
print(isinstance('hello', Animal)) # False
在doEat()方法中判断输入的参数 obj 是否为Animal 对象,只有Animal对象才能调用eat方法
# 函数
def doEat(obj):
if isinstance(obj, Animal):
obj.eat()
以后处理多态的代码时,都建议加上 isinstance() 的判断