一、面向对象 OOP
1. 基本介绍
面向对象是一种编程思想/写代码套路
-
⾯向过程
关注的是 具体步骤的实现, 所有的功能都⾃⼰书写
亲⼒亲为
定义⼀个个函数, 最终按照顺序调⽤函数 -
⾯向对象
关注的是结果, 谁(对象) 能帮我做这件事
偷懒
找⼀个对象(), 让对象去做
2. 类和对象
- 类
class 类名:
# 在缩进中书写的内容,都是类中的代码
def ⽅法名(self): # 就是⼀个⽅法
pass
- 对象
对象 = 类名()
- 调⽤⽅法
对象.⽅法名()
3. self 的介绍
- 从函数的语法上讲, self是形参, 就可以是任意的变量名,只不过我们习惯性将这个形参写作 self
- self 是普通的形参, 但是在调⽤的时候没有传递实参值,原因是, Python 解释器在执⾏代码的时候, ⾃动的将调⽤这个⽅法的对象 传递给了 self, 即 self 的本质是对象
- 验证, 只需要确定 通过哪个对象调⽤, 对象的引⽤和 self的引⽤是⼀样的
- self 是函数中的局部变量, 直接创建的对象是全局变量
对象 调⽤ ⽅法, 解释器就会将 对象传给 self
4. 对象的属性操作
(1)添加属性
- 类内部添加
在内部方法中,self 属于对象
self.属性名 = 属性值
统一在__init__
方法中添加类的属性
- 类外部添加
对象.属性名 = 属性值 # 一般不用
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def infoCat(self):
print(self.name, self.age)
mimi = Cat('meow', 18)
mimi.infoCat() # meow 18
(2)获取属性
对象.属性名
- 类内部
self.属性名
- 类外部
对象.属性名 # 比较少操作
5. 魔法方法
魔法方法概念:⼀类⽅法, 以两个下划线开头,两个下划线结尾,并且在满⾜某个条件的情况下, 会⾃动调⽤, 这类⽅法称为 魔法⽅法。
(1)__init__
有什么⽤, ⽤在哪
- 给对象添加属性的, (初始化⽅法, 构造⽅法)
- 某些代码, 在每次创建对象之后, 都要执⾏,就可以将这⾏代码写在 init ⽅法
- 书写的注意事项
如果 init ⽅法中,存在出了 self之外的参数, 在创建对象的时候必须传参
传参举例:
形参name、age:def __init__(self, name, age):...
调用传参:mimi = Cat('meow', 18)
(2)__str__
- 自动打印对象的信息
__str__
方法要有return值
- 调用的时候使用
print(对象)
的方式 - 没有的话使用print对象会直接打印出地址
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return (f'小猫名字是{self.name},年龄是{self.age}')
mimi = Cat('meow', 18)
print(mimi) # 小猫名字是meow,年龄是18
(2)了解即可__del__
- 对象被删除销毁的时候会自动调用(‘遗言’)
- 调⽤场景, 程序代码运⾏结束, 所有对象都被销毁
- 调⽤场景, 直接使⽤ del 删除对象(如果对象有多个名字(多个对象引⽤⼀个对象),需要吧所有的对象都删除才⾏ )
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def __del__(self):
print(f'{self.name}已被销毁')
mimi = Cat('meow', 18)
del mimi # meow已被销毁
6. 案例练习
(1)封装家具(对象)
# 家具类
class HouseItem:
def __init__(self,name,area):
# 家具名
self.name = name
# 家具面积
self.area = area
# 房子类
class House:
def __init__(self,name,area):
self.name = name
self.area = area
self.left_area = area
self.item_list = []
def addItem(self, item):
# 添加家具
if (self.left_area>item.area):
self.item_list.append(item.name)
print(f'提示:家具{item.name}已被添加进房子')
# 修改剩余面积
self.left_area = self.area - item.area
else:
print(f'提示:剩余面积不足,家具{item.name}无法添加进房子')
def __str__(self):
return f'房子户型是:{self.name},总面积是:{self.area},余下面积为{self.left_area}\n'\
f'加入的家具有:{self.item_list}'
# 房子实例化
newHouse = House('普通平房', 130) # 房子总面积
# 家具类的实例化
bed = HouseItem('席梦思', 4)
chest = HouseItem('衣柜', 2)
table = HouseItem('餐桌', 130)
# 将实例化的家具加进房子中
newHouse.addItem(bed)
newHouse.addItem(chest)
newHouse.addItem(table)
# 输出房子信息
print(newHouse)
'''
提示:家具席梦思已被添加进房子
提示:家具衣柜已被添加进房子
提示:剩余面积不足,家具餐桌无法添加进房子
房子户型是:普通平房,总面积是:130,余下面积为128
加入的家具有:['席梦思', '衣柜']
'''
7. 私有属性&私有方法
- 私有权限
在类内部, 属性名或者方法名 前边加上两个 下划线
eg: self.__age
, 这个属性或者方法 就变为 私有的
私有的方法和属性, 只能在当前类的内部使用
对象.__dict__
魔法属性, 可以将对象具有的属性组成字典返回
8. 继承
- 继承描述的是类与类之间的关系
- 继承的好处: 减少代码的冗余(相同的代码不需要多次重复书写), 可以直接使用
# class A(object):
class A: # 没有写父类,但也有父类, object, object 类是 Python 中最顶级(原始)的类
pass
class B(A): # 类 B, 继承类 A
pass
- 术语
A 类, 称为是 父类(基类)
B 类, 称为是 子类(派生类) - 单继承
一个类只继承一个父类,称为单继承 - 继承之后的特点
子类(B)继承父类(A)之后, 子类的对象可以直接使用父类中定义的公有属性和方法
class animal:
def eat(self):
print('animal eat')
class dog(animal):
def say(self):
print('狗 叫')
class minidog(dog):
pass
kitty = minidog()
kitty.say()
kitty.eat()
'''
继承父类方法
狗 叫
animal eat
'''
(1)重写
- 覆盖
- 拓展
super().say()
class animal:
def eat(self):
print('animal eat')
class dog(animal):
def say(self):
print('狗 叫')
class minidog(dog):
# 直接重写
def say(self):
pass
# 拓展
def say(self):
print('拓展内容')
super().say()
pass
kitty = minidog()
kitty.say()
kitty.eat()
9. 多态[了解]
- 同一个方法,传入不同的对象,执行得到不同的结果
- 哪个对象调用方法, 就去自己的类中去查找这个方法, 找不到去父类中找
10. 属性&对象
- 实例对象
- 通过 类名() 创建的对象, 我们称为实例对象,简称实例
- 创建对象的过程称为是类的实例化
- 我们平时所说的对象就是指 实例对象(实例)
- 每个实例对象, 都有自己的内存空间, 在自己的内存空间中保存自己的属性(实例属性)
- 类对象
- 类对象 就是 类, 或者可以认为是 类名
- 类对象是 Python 解释器在执行代码的过程中 创建的
- 类对象的作用:
① 使用类对象创建实例 类名(),
② 类对象 也有自己的内存空间, 可以保存一些属性值信息 (类属性)- 在一个代码中, 一个类 只有一份内存空间
class Doggie:
# 类属性
count = 0
# self.name 实例属性
def __init__(self,name):
self.name = name
# 每创建一个对象,就让count+1
Doggie.count+=1
doggie1 = Doggie('ww')
print(doggie1.count) # 1
doggie2 = Doggie('w2w')
print(doggie1.count) # 2
print(doggie2.count) # 2
11. 方法的划分
def
定义的就是方法- 实例方法(常用)
# 在类中直接定义的方法 就是 实例方法
class Demo:
def func(self):
# 参数一般写作 self,表示的是实例对象
pass
需要使用
self
的时候,必须使用实例方法
使用:类名.方法名()
- 类方法(少用)
@classmethod 装饰器(使用 @classmethod 装饰的方法)
# 在方法名字的上方书写 @classmethod 装饰器(使用 @classmethod 装饰的方法)
class Demo:
@classmethod
def func(cls):
# 参数一般写作 cls, 表示的是类对象(即类名) class
pass
- 前提, 方法中不需要使用 实例属性(即 self)
- 用到了类属性, 可以将这个方法定义为类方法,(也可以定义为实例方法)
- 使用:
类名.方法名() || 实例.方法名()
- 静态方法(基本不用)
@staticmethod 装饰器(使用 @staticmethod 装饰的方法)
class Demo:
@staticmethod
def func():
# 一般没有参数
pass
- 案例举例
@staticmethod
def show_help():
print('显示游戏的帮助信息')
@classmethod
def show_top_score(cls):
print(f'游戏最高分是:{cls.top_score}')
12. 哈希
- hash:对一个数据产生一个唯一的值(‘指纹’),不可逆的
is
判断连个对象是不是同一个对象,引用是否相同
a is b <===> id(a) == id(b)
- 面试
== 只判断数据值是否相同, is 判断引用是否相同