案例二:封装
需求:
类名:房子类House
属性:户型 name , 总面积 area , 剩余面积free_area,家具名称列表item_list
方法:__init__ ,__str__
添加家具方法
def add_item(self,item): # item 家具对象
先判断房子的剩余面积和总面积的关系
修改房子的剩余面积
修改房子的家具列表名称
类名: 家具类HouseItem
属性:名字name , 占地面积area
方法:__init__ ,__str__
# 定义家具类
class HouseItem:
def __init__(self, name, area):
self.name = name
self.area = area
def __str__(self):
return f"家具名字{self.name},占地面积{self.area}平米"
# 创建房子
class House:
def __init__(self, name, area):
self.name = name
self.total_area = area
self.free_area = area # 剩余面积
self.item_list = []
def __str__(self):
return f"户型:{self.name},总面积:{self.total_area}平米" \
f"剩余面积{self.free_area}平米,家具名称列表:{self.item_list}"
def add_item(self, item):
# 判断房子的剩余面积和家具的占地面积之间的关系
# self 表示的 房子的对象,缺少一个家具对象使用传参解决
if self.free_area > item.area:
# 添加家具,---》像列表添加数据
self.item_list.append(item.name)
# 修改剩余面积
self.free_area -= item.area
print(f"{item.name}添加成功")
else:
print('剩余面积不足,换个大房子')
# 创建家具
bed = HouseItem('席梦思', 4)
chest = HouseItem('衣柜', 2)
table = HouseItem('餐桌', 1.5)
print(bed)
print(chest)
print(table)
# 创建房子对象
house = House('三室一厅', 320)
print(house)
# 添加 床
house.add_item(bed)
print(house)
输出:
家具名字席梦思,占地面积4平米
家具名字衣柜,占地面积2平米
家具名字餐桌,占地面积1.5平米
户型:三室一厅,总面积:320平米,剩余面积320平米家具名称列表:[]
席梦思添加成功
户型:三室一厅,总面积:320平米,剩余面积316平米家具名称列表:['席梦思']
…
类名:电脑类 Computer
属性:品牌 brand 价格 price
方法:play_movie
class Computer:
def __init__(self,brand,price):
self.brand = brand
self.price = price
def play_movie(self,movie):
print(f'{self.brand}播放电影{movie}')
mi = Computer('小米',4389)
mac = Computer('Mac',12999)
mi.play_movie('西游记')
mac.play_movie('变形金刚')
…
Alt+回车 添加self之外的属性
15.11、私有和公有
1.在python中定义的方法和属性,可以添加访问控制权限(即在什么地方可以使用这个属性和方法)
2.访问控制权限分为两种,共有权限,私有权限
3.共有权限
直接书写的方法和属性,都是公有的
公有的方法和属性,可以在任意地方访问和使用
4.私有权限
在类内部,属性名或者方法名 前面加上两个下划线,这个属性或方法就变为私有的
私有的方法和属性,只能在当前类的内部使用
5.什么时候定义私有
1.某个属性或者方法,不想在 类外部被访问和使用,就将其定义为私有即可
2.测试中,一般不怎么使用,直接公有即可
3.开发中,会根据需求文档,确定什么作为私有
6.若想在类外部操作私有属性,方法是,在类内部定义公有的方法,通过这个方法去操作
案例:
定义一个Person类,属性name,age(私有)
class Person:
def __init__(self, name, age):
self.name = name
# self.age = age # 年龄
# 私有的本质,是python解释器执行代码,发现属性或方法名前有两个_,会将这个名重命名
# 会在这个名字前面加上 _ 类名前缀,即self.__age ===> self._Person__age
self.__age = age # 将其定义为私有属性,属性名前加上两个_
def __str__(self):
return f"名字:{self.name},年龄:{self.__age}"
xm = Person('小明', 18)
print(xm) # 名字:小明,年龄:18
# print(xm.age) # 在类外部直接访问age属性,
# print(xm.__age) # 会报错,在类外部不能直接使用私有属性
# xm.age = 20 # 直接修改age属性
xm.__age = 22 # 这个不是修改私有属性,是添加一个公有的属性 __age
print(xm) # 名字:小明,年龄:18
print(xm._Person__age) # 能用但是不要用 # 18
xm._Person__age = 19
print(xm) # 名字:小明,年龄:19
补充 :
对象.__dict 魔法属性,可以将对象具有的属性组成字典返回
15.12、继承
面向对象三大特性
封装 根据职责将属性和方法封装到一个抽象的 类 中
继承 实现代码的重用,相同的代码不需要重复的编写
多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
继承
继承描述的是类与类之间的关系
继承的好处:减少代码的冗余(相同的代码不需要多次重复书写),可以直接使用
语法
class A: # 没有写父类,但也有父类,object,object类是python中最顶级的类
pass
class B(A): # 类B,继承类A
pass
术语:
1.A类称为 父类(基类)
2.B类,称为子类(派生类)
单继承:一个类值继承一个父类,称为单继承
继承之后的特点:
子类继承父类之后,子类的对象可以直接使用父类中定义的公有属性和方法
案例
1.定义一个 动物类,吃
2.定义一个狗类,继承动物类,吃,叫
3.定义一个 哮天犬类 ,继承 狗类
# 定义一个动物类,吃东西
class Animal:
def eat(self):
print('吃东西')
# 定义一个 狗类 继承动物类 汪汪叫
class Dog(Animal):
def bark(self):
print('汪汪汪')
# 定义一个 哮天犬类
class XTQ(Dog):
pass
# 创建一个animal对象
ani = Animal()
ani.eat()
# 创建一个狗类 对象
dog = Dog()
dog.bark()
dog.eat()
# 创建一个哮天犬对象
xtq = XTQ()
xtq.bark()
xtq.eat()
结论
python 中 对象.方法() 调用方法
1.先在自己的类中去找有没有这个方法,如果有,直接调用
2.如果没有去父类中 查找,如果有直接调用
3.如图过没有,去父类发父类中查找,如果有直接调用
4. 。。。
5.如果object类中有,直接调用,如果没有代码报错
15.13、重写
重写: 在字类中定义了和父类中名字相同的方法,就是重写
原因:父类中的方法,不能满足子类对象的需求,所以重写
特点:调用字类字节的方法,不在调用父类中的方法
方式:
1.覆盖(父类中功能完全抛弃,不要重写书写)
2.扩展(父类中功能还调用,只是添加一些新功能)(使用较多)
覆盖
1.直接在字类中 定义父类中名字相同的方法
2.直接在方法中书写新的代码
class Dog:
def bark(self):
print('汪汪汪')
class XTQ(Dog):
# XTQ 类 bark 不在汪汪汪叫,改为嗷嗷嗷
def bark(self):
print('aoaooa')
xtq = XTQ()
xtq.bark()
扩展父类中的功能
1.直接在子类中 定义父类中名字相同的方法
2.在合适的地方调用 父类中方法 super().方法()
3.书写添加的功能
class Dog:
def bark(self):
print('汪汪汪')
class XTQ(Dog):
# XTQ 类 bark 不在汪汪汪叫,改为嗷嗷嗷
def bark(self):
print('aoaooa')
# 1.先嗷嗷嗷叫 2.汪汪汪叫(父类中功能) 3.嗷嗷叫
# 调用父类中的代码
super().bark()
print('嗷嗷')
xtq = XTQ()
xtq.bark()
15.14、多态(了解
1.是一种写代码,调用的一种技巧
2.不同的对象调用相同的方法 ,得到不同结果 就是多态
3.多态可以增加代码的灵活度
哪个对象调用方法,就去自己的类中去查找这个方法,找不到就去父类中去找
15.15、属性和方法
python中一切皆对象。即使用class 定义的类 也是一个对象
对象的划分
-
实例对象(实例)
1.通过类名() 创建的对象,我们称为实例对象 简称实例 2.创建对象的过程称为是类的实例化 3.对象 就是指实例对象 4.每个实例对象,都有自己的内存空间,在自己的内存空间保存自己的属性(实例属性)
-
类对象
1.类对象 就是 类,或者可以认为是 类名 2.类对象是 python 解释器 在执行代码的过程中 创建的 3.类对象的作用:使用类对象创建实例 类名() , 类对象 也有自己的内存空间,可以保存一些属性值信息(类属性) 4.在一个代码中,一个类 只有一份内存空间
属性的划分
-
实例属性
实例对象具有的属性 定义和使用 在init方法中,使用self.属性名 = 属性值 定义 在方法中 使用 self.属性名 来获取(调用) 内存 实例属性,每个实例中都存在一份 使用时机 基本上99%都是实例属性,即通过self 去定义 找多个对象,来判断这个值是不是都是一样的,如果都是一样的,同时变化,则一般定义为类属性,否则定义 为 实例属性
-
类属性
类对象具有的属性 定义和使用 在类内部,方法外部,直接定义的变量,就是类属性 使用:类对象.属性名 = 属性值 or 类名.属性名 = 属性值 类对象.属性名 or 类名.属性名 内存 只有 类对象 中存在一份
# 定义一个dog类,定义一个类属性count,
# 用来记录创建该类对象的个数(即每创建一个对象,count的值就要加1)实例属性 name
class Dog:
# 定义类属性
count = 0
# 定义实例属性,init方法中
def __init__(self, name):
self.name = name # 实例属性
# 因为每创建一个而对象,就会调用init 方法,就将个数加1的操作,写在init方法中
Dog.count += 1
# 在类外部
# 打印输出目前创建几个对象
print(Dog.count) # 0
dog1 = Dog('小花')
print(Dog.count) # 打印输出目前创建几个对象 # 1
dog2 = Dog # 不是创建对象,个数不变的
dog3 = dog1 # 不是创建对象,个数不变
print(Dog.count)
dog4 = Dog('团团') # 创建一个对象,个数+1
print(Dog.count) # 2
# 补充: 可以使用 实例对象.类属性名 来获取类属性的值
# (原因 实例对象属性的查找顺序,先在实例属性中找,找到直接使用
# 没有找到会去类属性中找,找到可以使用,没有找到 报错
print(dog1.count) # 2
print(dog4.count) # 2
方法的划分
方法使用 def 关键字定义在类中的函数就是方法
-
实例方法(常用
定义
# 在类中直接定义的方法 就是 实例方法 class Demo: def func(self): # 参数一般写作 self,表示的是实例对象 pass
定义时机
如果在方法中许哟使用实例属性(即self),则这个方法必须定义为 实例方法
调用
对象.方法名() # 不需要给self传参
-
类方法(会用
定义
# 在方法名字的上方书写 @classmethod 装饰器(使用 @classmethod 装饰的方法) class Demo: @classmethod def func(cls): # 参数一般写作cls, 表示的是类对象(即类名) class pass
定义时机
前提 方法中不需要使用实例属性 用到了类属性 可以将这个方法定义为类方法(也可以定义为实例方法)
调用
# 1,通过类对象调用 类名.方法名() # 不需要给cls 传参 # 2, 通过实例对象调用 实例.方法名() # 不需要给cls传参
-
静态方法(基本方法
定义
# 在方法名的上方书写@staticmethod 装饰器 (使用 @staticmethod 装饰的方法) class Demo: @staticmethod def func(): # 一般没有参数 pass
定义时机
前提 方法不使用 实例属性(即self) 也不使用类属性,可以将这个方法定义为 静态方法
调用
# 1,通过类对象调用 类名.方法名() # 不需要给cls 传参 # 2, 通过实例对象调用 实例.方法名() # 不需要给cls传参
练习Game
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-psygTYq7-1651569728573)(C:\Users\LIUBO\AppData\Roaming\Typora\typora-user-images\1651561329108.png)]
基本版本
import random
class Game:
top_score = 0 # 类属性,游戏的最高分
def __init__(self, name):
self.name = name # 定义实例属性name
def show_help(self):
print('这是游戏的帮助信息')
def show_top_score(self):
print(f'游戏的最高分:{Game.top_score}')
def start_game(self):
print(f'{self.name} 开始一局游戏', end='')
score = random.randint(10, 100) # 本次游戏的得分
print(f'本次游戏得分{score}')
if score > Game.top_score:
Game.top_score = score # 修改最高分
else:
pass
xw = Game('小于')
xw.start_game()
xw.show_top_score()
xw.start_game()
xw.show_top_score()
优化 部分使用静态方法和类方法
@staticmethod # 静态方法
def show_help():
print('这是游戏的帮助信息')
@classmethod # 类方法
def show_top_score(cls):
print(f'游戏的最高分:{Game.top_score}')
补充
哈希(hash): 是一个算法,可以对数据产生一个唯一的值(指纹)
is 可以用来判断两个对象是不是同一个对象,即 两个对象的应用是否相同
a is b ===> id(a) == id(b)
面试中可能会问: is 和 == 的区别?
== 只判断数据值是否相同,is 判断引用是否相同