嵌入式Python高级 str字符串 set集合 dict字典 slice切片 推导式 高级变量公共语法 内置函数 面向对象 __int__ __str___ 私有化 属性私有化 方法私有化 面向对象三大特征 封装 继承 多态
一、str字符串
字符串就是一串字符,是编程语言中表示文本的数据类型
1. 字符串定义
Python中可以使用一对双引号或者一对单引号定义字符串
str1 = 'hello'
str2 = "hello"
2. 获取字符串中元素
和列表一样,字符串也是通过索引获取元素
str = "hello"
# 获取第三个元素
ele = str[2] # l
3. 遍历字符串
可以通过for
循环遍历字符串
str = 'hello'
for ele in str:
print(ele)
4. 字符串的常见操作
4.1. 判断
4.2. 查找替换
4.3. 切割
4.4. 去空白
5. 练习-用户名和密码校验
需求
- 用户名和密码格式校验程序
- 要求从键盘输入用户名和密码,分别校验格式是否符合规则
- 如果符合,打印
用户名合法
,密码合法
- 如果不符合,打印出不符合的原因,并提示重新输入
- 用户名长度
6-20
,用户名必须以字母开头- 密码长度至少
6
位,不能为纯数字,不能有空格
分析
1.从键盘输入用户名(需要while循环)
2.长度6-20
3.必须字母开头4.输入密码(while循环)
5.密码长度至少6位
6.不能为纯数字
7.不能有空格
实现
while True:
# 1.从键盘输入用户名(需要while循环)
name = input('请输入用户名:')
# 2.长度6-20
if not (len(name) >= 6 and len(name) <= 20):
print('用户名必须6到20位')
continue
# 3.必须字母开头 ab A-Z
# 获取第一个字母 是否是a-z A-Z a
ele = name[0]
if not ele.isalpha():
print('用户名第一个必须为字母')
continue
# 用户名满足
print('用户名合法')
break
# 4.输入密码(while循环)
while True:
pwd = input('请输入密码')
# 5.密码长度至少6位
if len(pwd) < 6:
print('密码长度至少为6位')
continue
# 6.不能为纯数字
if pwd.isdecimal():
print('密码不能为纯数字')
continue
# 7.不能有空格
# ' 张 三 '
if ' ' in pwd:
print('密码不能有空格')
continue
print('密码合法')
break
扩展
isalpha()
字符串中所有元素都是字母,则返回Trueisdecimal()
字符串中都是数字,则返回True
二、set集合
set
被称为集合,是无序的,并且集合中的元素是唯一的
1. 集合的创建
s = {'张三','李四','王五'}
集合是无序的
s = {'张三','李四','王五'}
print(s)
结果:
{'王五', '张三', '李四'}
集合元素唯一
s = {'张三','李四','王五','张三'}
print(s)
结果:
{'李四', '张三', '王五'}
2. 遍历集合中元素
通过for
循环遍历集合中的元素
s = {'张三','李四','王五'}
# 遍历集合
for ele in s:
print(ele)
3. 集合中添加元素
集合可以通过add
方法添加元素
s = {'张三','李四','王五'}
# # 添加赵六 add
s.add('赵六')
4. 集合删除元素
remove
删除,如果有 直接删除,如果没有 程序报错
s = {'张三','李四','王五'}
# 删除张三
s.remove('张三')
pop
删除,随机删除集合中的元素并返回,如果集合中没有元素,则程序报错
s = {'张三','李四','王五'}
# pop 随机删除
print(s.pop())
discard
删除,元素存在则直接删除,如果元素不存在,则不做任何操作
s = {'张三','李四','王五'}
# discard 删除元素 如果元素不存在,不做任何处理
s.discard('林青霞')
三、dict字典
1. 字典简介
dictionary(字典) 是 除列表以外 Python 之中 最灵活 的数据类型,类型为dict
- 字典同样可以用来存储多个数据
- 字典使用键值对存储数据
2. 字典的定义
- 字典用
{}
定义- 键值对之间使用
,
分隔- 键和值之间使用
:
分隔
d = {'中国':'China','英国':'England','美国':'America'}
3. 字典的特点
字典中的键相当于索引,必须是唯一的
d = {'中国':'China','英国':'England','美国':'America','美国':'USA'}
print(d)
运行:
{'中国': 'China', '英国': 'England', '美国': 'USA'}
4. 字典增删改查
4.1. 增加
字典增加元素
d = {'中国':'China','英国':'England','美国':'America'}
# 添加 法国
d['法国'] = 'France'
也可以通过setdefault方法添加
d.setdefault('法国','France')
4.2. 删除
字典删除元素
d = {'中国':'China','英国':'England','美国':'America'}
# 删除美国 如果键不在字典中,会报错
del d['法国']
也可以通过pop删除
# pop 删除元素 并且返回删除元素的值 如果删除不存在会报错
result = d.pop('法国')
清空字典
# 清空容器中的数据 还可以继续使用
d.clear()
4.3. 修改
修改字典中元素
d = {'中国':'China','英国':'England','美国':'America'}
# 修改美国
d['美国'] = 'USA'
4.4. 查询
查询元素
d = {'中国':'China','英国':'England','美国':'America'}
# 查找中国
value = d['中国']
print(value)
5. 字典遍历
5.1. 遍历所有的键值对
通过for
循环遍历字典所有的键值对
d = {'中国':'China','英国':'England','美国':'America'}
for ele in d:
print(ele,d[ele])
结果:
中国 China
英国 England
美国 America
5.2. 遍历所有的键
d = {'中国':'China','英国':'England','美国':'America'}
for key in d.keys():
print(key)
结果:
中国
英国
美国
5.3. 遍历所有的值
d = {'中国':'China','英国':'England','美国':'America'}
for value in d.values():
print(value)
结果:
China
England
America
5.4. 遍历所有的键值对
d = {'中国':'China','英国':'England','美国':'America'}
for key,value in d.items():
print(key,value)
结果:
中国 China
英国 England
美国 America
6. 字典的应用场景
使用多个键值对,存储描述一个物体的相关信息---描述更复杂的数据信息
d = {'name':'张三','phone':'12332','age':40,'性别':'男'}
四、slice切片
1. 切片简介
取一个str
、list
、tuple
的部分元素是非常常见的操作
- 切片 译自英文单词
slice
,指的是一部分- 切片 根据 步长
step
从原序列中取出一部分元素组成新序列- 切片适用于 字符串、列表、元组
2. 切片的格式
字符串[开始索引:结束索引:步长]
包含开始索引, 不包含结束索引
2.1. 需求
string = '中华人民共和国欢迎您'
获取前三个文字
2.2. 代码
string = '中华人民共和国欢迎您'
# 获取前三个文字
newStr = string[0:3:1]
步长默认为1,可以省略,如下
newStr = string[0:3]
开始索引为0,可以省略,如下
newStr = string[:3]
如果到末尾结束,可以省略结束索引,例如取后三个字“欢迎您”
newStr = string[7:]
3. 索引的正序和倒序
索引分为正序和倒序
- 正序:从左向右,
0
开始- 倒序:从右向左,
-1
开始
3.1. 需求
ss = "中华人名共和国欢迎您"
把字符串中从第一个到倒数第二个(不包含)打印出来
3.2. 代码
ss = "中华人名共和国欢迎您"
# 把字符串中从第一个到倒数第二个(不包含)打印出来
# 开始位置:正序 结束位置:倒序
print(ss[:-2])
4. 步长为负数
步长也可以为负数,代表逆序切片
4.1. 需求
ss = "中华人名共和国欢迎您"
把从角标为2到7(包含)倒序打印出来
4.2. 代码
ss = "中华人民共和国欢迎您"
# 把从角标为2到7(包含)倒序打印出来
# 欢国和共名人
print(ss[7:1:-1])
注意:步长为负,索引也应该逆序索引
五、推导式
推导式指的是轻量级循环创建数据的方式,对列表或可迭代对象中的每个元素应用某种操作,用生成的结果创建新的列表;或用满足特定条件的元素创建子序列。
推导式包括:
- 列表推导式
- 元组推导式
- 集合推导式
- 字典推导式
1. 列表推导式
列表推导式的格式:[计算公式 for循环 if判断]
通过列表推导式快速创建[1, 11)
所有数字的列表
lst = [ele for ele in range(1, 11)]
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
通过列表推导式快速创建[1, 11)
所有偶数的列表
lst = [ele for ele in range(1, 11) if ele % 2 == 0]
# [2, 4, 6, 8, 10]
通过列表推导式快速创建[1, 11)
所有偶数的平方的列表
lst = [ele ** 2 for ele in range(1, 11) if ele % 2 == 0]
# [4, 16, 36, 64, 100]
2. 元组推导式
元组推导式的格式:(计算公式 for循环 if判断)
,其他与列表推导式一致
tp =(ele for ele in range(1, 11))
3. 集合推导式
集合推导式的格式:{计算公式 for循环 if判断}
,其他与列表推导式一致
s = {ele for ele in range(1, 11)}
4. 字典推导式
d = {key:value for key, value in zip(range(1,10),range(21,30))}
zip(..., ...)
将range(1,10)
和range(21,30)
里的每个元素一一组合成元组
(1, 21)
(2, 22)
(3, 23)
...
(8, 28)
(9, 29)
再把这些元组打包成一个可迭代对象。
5. 推导式练习
5.1. 需求
请写出一段 Python 代码实现分组一个 list 里面的元素
比如 [1,2,3,...100] 变成 [[1,2,3],[4,5,6]....[100]]
5.2. 分析
需要将列表中三个元素一组分隔,剩下的最后一组,其实就是对列表进行切片操作
5.3. 代码
# 创建列表
lst = [ele for ele in range(1, 101)]
# 切片 0:3 3:6 6:9
newL = [lst[ele:ele + 3] for ele in range(0, len(lst)) if ele % 3 == 0]
print(newL)
六、高级变量类型的公共语法
1. 内置函数
高级变量类型有一些公共的内置函数,如下
len 长度
str = 'hello'
print(len(str))
结果:
5
del 删除
lst = [1,2,3]
del lst[0]
print(lst)
结果:
[2,3]
2. 运算符
2.1. in
和not in
str = 'hello'
# h是否在str中
result = 'h' in str
print(result)
result = 'h' not in str
print(result)
结果:
True
False
2.2. +
合并
只有字符串、列表、元组可以合并
# 字符串
str1 = 'hello'
str2 = 'world'
str = str1 + str2
字符串
# 字符串
str1 = 'hello'
str2 = 'world'
str = str1 + str2
列表
lst1 = [1,2,3]
lst2 = [4,5,6]
lst = lst1 + lst2
元组
t1 = (1,2,3)
t2 = (4,5,6)
t = t1 + t2
2.3. *
重复
只有字符串、列表、元组可以
str = 'hello'
print(str*3)
l = [1,2,3]
print(l * 3)
t = (1,2,3)
print(t * 3)
结果:
hellohellohello
[1, 2, 3, 1, 2, 3, 1, 2, 3]
[1, 2, 3, 1, 2, 3, 1, 2, 3]
七、综合练习1-1
字符串逆序统计
需求:
完成字符串的逆序以及统计
设计一个程序,要求只能输入长度低于31的字符串,否则提示用户重新输入
打印如下内容:
--------------------------------------------
您输入的字符串: zhongshanshan
长度: 13
逆序后为: nahsnahsgnohz
字符统计结果: z:1 h:3 o:1 n:3 g:1 s:2 a:2
--------------------------------------------
分析
1. 输入字符串(while循环)
2. 字符串长度小于31位,否则提示重新输入
3. 您输入的字符串: ...
4. 长度: ...
5. 逆序后为: ... (切片)
6. 字符统计结果: ...(afsfdsf) a:1 f:3 s:2 d:1
代码
while True:
# 1.输入字符串(while循环)
str = input('请输入字符串:')
# 2.字符串长度小于31位,否则提示重新输入
if len(str) >= 31:
print('不能超过31位,请重新输入')
continue
# 跳出循环
break
print('输入正确')
print("--------------------------------------------")
# 3.您输入的字符串: ...
print('您输入的字符串:%s' % str)
# 4.长度: ...
print('长度:%d' % len(str))
# 5.逆序后为: ... (切片)
newStr = str[::-1]
print('逆序后为:%s' % newStr)
# 6.字符统计结果: ...(afsfadsf) a:1 f:3 s:2 d:1
# 1.字典 保存结果 {}
resultDict = {}
for ele in str:
if ele not in resultDict:
# 2. 如果字典中没有这个a, 把a添加进去 {'a':1}
resultDict[ele] = 1
else:
# 3.字典中有a 将元素个数+1
resultDict[ele] += 1
print('字符统计结果:{}'.format(resultDict))
print("--------------------------------------------")
八、面向对象
1. 面向对象和面向过程思想
面向对象和面向过程都是一种编程思想,就是解决问题的思路
- 面向过程:
POP(Procedure Oriented Programming)
面向过程语言代表是c语言- 面向对象:
OOP(Object Oriented Programming)
常见的面向对象语言包括:java c++ go python koltin
通过面向对象的方式,我们不再关注具体的步骤,而是将问题抽象为对象和它们之间的交互。我们可以直接调用对象的方法来实现功能,而无需显式指定每个步骤。
面向过程强调按照步骤执行操作,而面向对象强调通过定义和操作对象来解决问题。
在面向对象的编程中,我们将问题抽象为对象的集合,这些对象具有属性和行为,并通过对象之间的交互来实现功能。这种抽象和交互的方式使得面向对象编程更加灵活、可维护和可扩展。
接下来我们看同一个问题,面向过程和面向对象是怎么解决的?
1.1. 面向过程编程的贪吃蛇游戏
在面向过程编程中,贪吃蛇游戏可能会以以下方式实现:
- 定义蛇的初始位置、长度、方向等变量。
- 创建一个表示游戏区域的二维数组。
- 在游戏循环中,根据用户输入改变蛇的方向。
- 更新蛇的位置,根据当前方向向前移动一格。
- 检查蛇是否吃到食物,如果是,则增加蛇的长度。
- 检查蛇是否撞到边界或自己的身体,如果是,则游戏结束。
- 在游戏区域中绘制蛇和食物。
- 循环回到第3步,直到游戏结束。
在面向过程的编程中,游戏的各个方面被划分为一系列的步骤和变量,通过按照特定顺序执行这些步骤来控制游戏的逻辑和状态。
1.2. 面向对象编程的贪吃蛇游戏
现在,让我们看看如何使用面向对象编程来实现贪吃蛇游戏。
- 创建一个
Snake
类,具有属性(例如位置、颜色、长度、方向)和方法(例如移动、吃食物)。- 创建一个
Food
类,具有属性(例如位置、颜色)。- 创建一个
Game
类,它包含一个或多个蛇对象和一个或多个食物对象,以及游戏区域等属性。Game类还具有控制游戏逻辑的方法,例如更新游戏状态和绘制游戏界面。- 在游戏循环中,通过调用Game类的方法来控制游戏的进行,例如根据用户输入改变蛇的方向,更新蛇的位置,检查碰撞等。
- 在游戏界面中,通过调用绘图方法来绘制蛇和食物。
在面向对象编程中,贪吃蛇游戏被视为一组对象的交互。各个对象封装了游戏的状态和行为,并通过对象之间的消息传递来实现功能。这种对【对象Object】的抽象和交互使得游戏逻辑更清晰、可维护性更高,并且可以轻松地扩展和修改游戏的功能。
1.3. 面向对象的总结
- 面向对象,强调的是对象(实体)
- 面向对象是一种思想,更加符合人的思维习惯
- 面向对象使复杂的问题简单化了
- 面向对象的出现,让曾经在过程的执行者,变成了对象的指挥者
2. 类和对象
类和对象是面向对象非常重要的概念
- 类是描述了一种类型(相当于图纸)
- 对象是这个类型的具体实现(相当于图纸具体实现)
思考:
旺财和狗,哪个是类,哪个是对象?
答案:
狗是一个类型,属于类
旺财是狗的实现,属于对象
类和对象的关系
类就是制造图纸,只有一个。对象是类的实体,会产生多个
定义类和创建对象
类的定义格式:
class 类名:
pass
创建对象
对象名 = 类名()
代码演示:
# 定义类
class Person:
pass
# 创建对象
p1 = Person()
3. 类的组成
类可以描述世间万物,类都需要有类名,也应该具备一些属性和行为
- 类的关键字:
class
- 类的名称:类名
- 类的属性:一组数据
- 类的方法:允许进行操作的方法(行为)
人(Person)类应该具备什么属性和行为呢?
- 属性:姓名(
name
) 、年纪(age
)- 方法:吃(
eat
)、跑(run
)、说话(say
)
3.1. 成员属性
成员属性的定义需要在初始化方法__init__
方法下定义
格式:
def __init__(self):
self.属性 = 属性值
举例:
class Person:
def __init__(self, name, age):
# 成员属性
self.name = name
self.age = age
# 创建对象
p = Person('张三', 30)
# 访问成员属性
print(p.name)
print(p.age)
在创建对象时,属性值可以由外部传进来,也可以在初始化方法里设置为任意值
3.2. 成员方法
成员方法的定义格式为 def 函数名(self):
class Person:
# 定义成员方法 say_hello
def say_hello(self):
print('hello')
# 定义成员方法run
def run(self):
print('跑')
# 创建对象
p = Person()
# 调用成员方法
p.say_hello()
注意:
成员方法都会默认有参数
self
,调用的时候不需要传递self
九、 特殊方法和参数
1. 成员方法的self
参数
成员方法中self
表示调用该方法的对象。
对象调用⽅法时,python解释器会把这个对象作为第⼀个参数传递给⽅法
通过self
也可以获取对象的属性,调用对象的其它成员方法
class Person:
def __init__(self, name, age):
# 定义成员属性
self.name = name
self.age = age
def say_hello(self):
# 通过self访问成员属性
print(self.name)
# 对象
p = Person('张三', 30)
p.say_hello()
2. __init__
方法
__init__
是一个内置的方法
当对象创建的时候就会自动执行__init__
方法
# 定义类
class Person:
def __init__(self):
print('执行了init方法')
# 创建对象
p1 = Person()
p2 = Person()
运行程序,输出:
执行了init方法
执行了init方法
一旦创建了该类的对象就会执行__init__
方法
3. __str__
方法
__str__
也是类的内置方法
用于将对象转化为适于人阅读的形式
先看一段代码:
class Person:
def __init__(self,name,age):
# 成员属性
self.name = name
self.age = age
# 创建对象
p1 = Person('张三',30)
p2 = Person('李四',40)
print(p1)
print(p2)
创建了两个对象,输出两个对象
结果:
<__main__.Person object at 0x03769D10>
<__main__.Person object at 0x03769FD0>
从结果中我们并不能区分出到底哪个是属于p1,哪个是属于p2
可以通过__str__
提取对象的主要特征用于区分不同的对象
class Person:
def __init__(self,name,age):
# 成员属性
self.name = name
self.age = age
def __str__(self):
'''
以字符串输出对象,把对象变成我们能够读懂的形式输出出来
:return:
'''
return 'name:{}, age:{}'.format(self.name,self.age)
# 创建对象
p1 = Person('张三',30)
p2 = Person('李四',40)
print(p1)
print(p2)
输出结果:
name:张三, age:30
name:李四, age:40
我们从结果中很容易就区分出两个对象的不同
十、私有化
将属性或者方法设置为不能在外部访问,就是私有化
私有化包括:属性私有化、方法私有化
1. 属性私有化
属性私有化格式,注意是两个下划线__
self.__属性名 = 属性值
class Circle:
def __init__(self,radius):
# 半径
self.radius = radius
# 私有化圆周率属性
self.__PI = 3.1415926
def perimeter(self):
'''
求圆的周长
:return: 圆的周长
'''
return 2 * self.__PI * self.radius
私有化作用:保证类中数据安全
2. 方法私有化
方法的私有化方式和属性私有化方式一样
class Person:
def __say_hello(self):
print('hello')
十一、面向对象三大特征
面向对象三大特征是:
●封装 (Encapsulation)
●继承 (Inheritance)
●多态 (Polymorphism)
1.封装
封装就是隐藏内部实现的细节,只保留功能接口
需求
定义一个洗衣机类,其中包含了打开/关闭洗衣机门、设置洗衣模式、设置马达转速、开始洗衣服等方法。
在初始化时,需要传入品牌brand和容量capacity两个参数。洗衣机门的状态is_closed、洗衣模式__mode和马达转速motor_speed都有默认值。
调用wash()方法时,会根据门的状态和模式来执行相应的操作,最终完成洗衣任务。
步骤:
1定义WashMachine类,初始化时传入品牌和容量两个参数,并设置默认值。
2定义打开/关闭洗衣机门的方法,通过修改is_closed属性来实现。
3定义设置洗衣模式的方法,通过修改__mode属性来实现。
4定义设置马达转速的私有方法,通过修改motor_speed属性来实现。
5定义开始洗衣服的方法,根据门的状态和模式来执行相应的操作,最终完成洗衣任务。
6实例化WashMachine类,传入品牌和容量两个参数,得到一个洗衣机对象。
7调用打开/关闭洗衣机门的方法,模拟打开/关闭洗衣机门的操作。
8调用设置洗衣模式的方法,传入一个参数,设置洗衣模式。
9调用开始洗衣服的方法,根据门的状态和模式来执行相应的操作,最终完成洗衣任务。
实现:
class WashMachine:
def __init__(self, brand, capacity):
"""
初始化
:param brand: 品牌
:param capacity: 容量
"""
self.brand = brand
self.capacity = capacity
# 是否关闭
self.is_closed = False
# 模式 0:未设定模式 1:轻揉模式 2:狂揉模式
self.__mode = 0
# 马达转速
self.motor_speed = 0
def open_door(self):
self.is_closed = False
print('打开洗衣机门')
def close_door(self):
self.is_closed = True
print('关闭洗衣机门')
def set_mode(self, new_mode):
"""
调节模式
:param new_mode:
:return:
"""
if new_mode not in [1, 2]:
print('设置模式错误')
else:
self.__mode = new_mode
def __set_motor_speed(self, speed):
"""
设置马达的转速
:param speed: 1000: 轻揉模式 2000:狂揉模式
:return:
"""
self.motor_speed = speed
def wash(self):
if not self.is_closed:
# 洗衣机门是否关闭 ,没有关闭 提示
print('请关闭洗衣机门,哔哔哔哔...')
return
elif self.__mode == 0:
print('请设置模式')
return
# 执行下面的操作
print('放水...')
print('放满了...')
if self.__mode == 1:
print('轻揉模式, 洗内衣')
# 调节马达转速
self.__set_motor_speed(1000)
print('马达转速:{}'.format(self.motor_speed))
print('开始洗...')
elif self.__mode == 2:
print('狂揉模式, 洗外套')
# 调节马达抓霉素
self.__set_motor_speed(2000)
print('马达转速:{}'.format(self.motor_speed))
print('开始洗...')
print('洗完了')
machine = WashMachine('海尔', 10)
machine.open_door()
machine.close_door()
machine.set_mode(2)
machine.wash()
封装的范围:
- 封装属性
- 封装成方法/函数
- 封装成类
- 封装模块和包
2. 继承
继承指的是一个对象直接使用另一个对象的属性或方法
继承的格式:class 子类名(父类名):
"""------------------ 定义Person类 ------------------"""
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hello(self):
print('hello from ', self.name)
"""------------------ 定义Student类继承Person ------------------"""
class Student(Person):
def __init__(self, name, age, height):
# 调用父类的初始化方法
super().__init__(name, age)
# 定义自己的属性
self.height = height
# 创建学生类
stu = Student('小明', 15, '180')
# 访问属性
print("name: {} age: {} height: {}".format(stu.name, stu.age, stu.height))
# 调用方法
stu.say_hello()
Student
类继承自Person
类
可以使用Person
类中定义的属性name
和age
以及方法say_hello
3. 多态
多态指的是一类事物有多种形态(一个类有多个子类)
多态的概念依赖于继承
中国人、美国人、非洲人都是属于Human人类的子类
对于Human来说有多个子类就称为多态
"""
多态案例
"""
# 父类
class Human:
def eat(self):
print('人类吃饭')
# 中国人
class ZhHuman(Human):
def eat(self):
print('中国人使用筷子吃饭')
# 美国人
class UsHuman(Human):
def eat(self):
print('美国人使用刀叉吃饭')
# 非洲人
class AfricaHuman(Human):
def eat(self):
print('非洲人直接用手吃恩希玛')
# 函数
def someone_eat(someone):
'''
接收一个具备吃eat功能的对象
'''
someone.eat()
# 创建四个对象
human = Human()
zh_human = ZhHuman()
us_human = UsHuman()
africa_huamn = AfricaHuman()
# 调用translate方法
someone_eat(human)
someone_eat(zh_human)
someone_eat(us_human)
someone_eat(africa_huamn)
someone_eat方法需要接收具备eat
功能的对象,但是由于ZhHuman
USHuman
AfricaHuman
都具备eat
功能(继承了Human)。所以也可以传递到someone_eat
方法中
4. 扩展知识
4.1. 鸭子类型
一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟可以被称为鸭子。这就是鸭子类型Duck Typing
对于上述多态中的的someone_eat
class Dog:
def eat(self):
print('狗吃骨头')
# 函数
def someone_eat(someone):
'''
接收一个具备吃eat功能的对象
'''
someone.eat()
dog = Dog()
someone_eat(dog)
someone_eat
需要传递一个具备eat
方法的对象,但是Dog
也具备eat
功能,所以也可以传递运行
这是由于python是动态类型语言,不能像C++、Java等静态类型语言一样,限制传递的数据类型
只要运行时发现dog对象有这个功能,就可以在函数中使用
4.2. 多继承
当一个类从多个父类继承属性和方法时,就称为多继承。
多继承格式:class 子类(父类1,父类2...)
下面是一个使用多继承的示例案例,展示了一个动物类和一个能飞的特性类和游泳的特性类:
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name} is eating.")
def sleep(self):
print(f"{self.name} is sleeping.")
class Flyable:
def fly(self):
print(f"{self.name} is flying.")
class Swimmable:
def swim(self):
print(f"{self.name} is swimming.")
class Duck(Animal, Flyable, Swimmable):
def __init__(self, name):
super().__init__(name)
duck = Duck("Donald")
duck.eat() # 输出: Donald is eating.
duck.sleep() # 输出: Donald is sleeping.
duck.fly() # 输出: Donald is flying.
duck.swim() # 输出: Donald is swimming.
在上面的示例中,Animal
是基类,Flyable
和Swimmable
是特性类。Duck
类通过多继承从这些类继承了属性和方法。通过调用这些继承的方法,我们可以看到Duck
对象具有吃、睡、飞和游泳的行为。
注意,在多继承的情况下,当多个父类中具有相同名称的方法时,解释器将按照方法解析顺序(Method Resolution Order,MRO)来确定使用哪个方法。在上述示例中,Python的默认MRO算法会按照类定义时的顺序来解析方法。在这个例子中,Duck
类首先从Animal
类继承方法,然后是Flyable
类,最后是Swimmable
类。
十二、搬家具进房子
1. 搬家具规则
家具
- 家具分不同的类型,并占用不同的面积
- 输出家具信息时,显示家具的类型和家具占用的面积
房子
- 房子有自己的地址和占用的面积
- 房子可以添加家具
- 如果房子的剩余面积可以容纳家具,提示家具添加成功;
- 否则提示添加失败
- 输出房子信息时,可以显示房子的地址、占地面积、剩余面积
- 查看房子中所有的家具
2. 类的设计
可以提取两个类:家具类Item
和房子类House
每个类具备的属性和方法如下:
3. 家具类
1.使用 Item 类可以创建 家具对象
2.家具有两个属性:
家具类型 type:字符串
家具面积 area:整数
3.实现__str__方法
4.显示家具的 type 和 area 属性
4. 房子类
1.使用 House 类可以创建 房子对象
2.房子有四个属性:
地址 address:字符串
房子面积 area:整数
房子剩余面积 free_area:整数,默认为房子的面积
家具列表 items:列表
3.实现__str__方法
显示房子的 address 、area、free_area 属性
4.实现add_item方法,提供item参数来添加家具
如果 可以容纳家具:
家具 加入 item属性
剩余面积 减少
如果 不能容纳家具: 提示家具添加失败
5. 主程序逻辑
1. 创建 家具对象, 输出 家具信息
2. 创建 房子对象, 输出 房子信息
3. 房子添加家具, 输出 房子信息
6. 代码实现
"""------------------ Item家具类 ------------------"""
class Item:
def __init__(self, type, area):
'''
创建家具类的初始化方法
:param type: 家具类型
:param area: 家具面积
'''
self.type = type
self.area = area
# def __str__(self):
# return 'str家具类型: {},家具占用面积: {}'.format(self.type, self.area)
def __repr__(self):
return 'repr家具类型: {},家具占用面积: {}'.format(self.type, self.area)
"""------------------ House房子类 ------------------"""
class House:
def __init__(self, address, area):
'''
房子的初始化方法
:param address: 房子地址
:param area: 房子面积
'''
self.address = address
self.area = area
# 剩余面积
self.free_area = self.area
# 家具列表
self.items = []
def __str__(self):
return '房子地址: {},占地面积: {},剩余面积: {}'.format(self.address, self.area, self.free_area)
def add_item(self, item):
"""
添加家具到房子中
:param item: 家具类Item的实例
:return:
"""
if self.free_area >= item.area:
# 家具添加到列表中
self.items.append(item)
# 修改剩余面积
self.free_area -= item.area
# 可以添加
print('添加成功')
else:
# 不能添加
print('面积不足, 不能添加家具')
# 创建家具
item1 = Item('桌子', 40)
item2 = Item('椅子', 10)
item3 = Item('家庭影院', 80)
print(item1)
print(item2)
print(item3)
# 创建房子
house = House('深圳湾一号', 100)
# 打印家具
print(house)
print("---------------------------------------------")
# 添加家具
house.add_item(item1)
house.add_item(item2)
house.add_item(item3)
print(house)
print("所有家具: ", house.items)
扩展:
__str__
方法返回一个友好的、可读性较高的字符串,主要用于用户可见的输出,强调可读性和易理解性。常用于直接__repr__
方法返回一个准确和详细的字符串,主要用于开发和调试过程中,强调准确性和完整性。常用于打印list
、set
、dict
等内部的所有对象