前言
最近ai势头正猛,公司也是要求学习ai了!自己先从Python入手,整理了份笔记,记录一下python语法。其语法和其他语言是相通的,只是写法不同。
一、字面量
- 所谓字面量,就是直接写在代码中的具体值
- Python的字符串中可以包含任意字符,且必须使用引号包起来。
- 字符串的引号,可以是:单引号、双引号、三个单引号、三个双引号。
- 写在Python文件头部的字符串,会被自动识别成docstring(文档字符串)
- 文档字符串的主要作用是:对当前Python文件进行一些说明,且文档字符串必须用三个双引号
"""python"""
"python"
'python'
'''python'''
二、变量
语法:变量名 = 值
name = '李四'
age = 18
height = '188'
print('你好!我叫' + name, '今年', age, '岁,身高' + height + 'cm。')
三、标识符命名规则
- 只能包含:数字、字母、下划线,且不能以数字开头,不能包含空格
- 标识符区分大小写,例如 Name和name是两个不同的标识符。
- 标识符不能使用关键字,
- 标识符尽量不要与内置函数同名。
- 标识符虽然没有长度限制,但应追求:简洁清晰,具有描述性。
| Python中的关键字 | ||||
|---|---|---|---|---|
| False | assert | continue | except | if |
| nonlocal | return | None | async | def |
| finally | import | not | try | True |
| await | del | for | in | or |
| while | and | break | elif | from |
| is | pass | with | as | class |
| else | global | lambda | raise | yield |
四、常量
一般约定全大写变量名来表示常量,涉及多个单词则以下划线分割。
python中没有强制的常量机制,其本质还是变量,只是约定好不要去修改!
# ctrl+shift+u 转换大小写
AGE = 13
NAME = 'abc'
五、数据类型
| 类型名称 | 英文名 | 举例 | 说明 |
|---|---|---|---|
| 字符串 | string | '李四' | 用引号包裹 |
| 整型 | int | 18 | 没有小数的数字 |
| 浮点型 | float | 20.26 | 有小数的数字 |
| ... |
type() 用来判断类型
print(type('李四')) # <class 'str'>
print(type(18)) # <class 'int'>
print(type(23.12)) # <class 'float'>
整型 int
# 整型:没有小数点的整数,可以是正数,负数,0
age = 18
age2 = 23.12
age3 = 0
# 当数很大时,可以使用下划线_,使数字易读
num = 10000
price = 100_000_999
# print(num, price)
# Python中整数值的上限,取决于执行代码的计算机的内存和处理能力
max_limit = 999 ** 9999
print(max_limit)
浮点型 float
# 浮点型就是带有小数的数字
height = 182.5
wight = 80.0
unit = -9.0
# 浮点型的科学计数法表示
speed = 3.4e+2 # 3.4乘以10的2次方 340.00
pi = 3.14e3 # 3.14乘以10的3次方 3140.
num_a = 5E8 # 5乘以10的8次方 500000000.0
num_b = 6E+6 # 6乘以10的6次方 6000000.0
num_c = 1E-2 # 1乘以10-2次方 0.01
num_d = 1e-3 # 1乘以10-3次方 0.001
字符串 string
字符串拼接
year = 2020
day = 6.20
school = '德州学院'
# 写法1:字符串之间以加号相连,但代码较乱且不能拼接数字
decr = '我毕业于' + school + ',毕业时间'
# 写法2:占位符 %s字符串 %i整数 %f浮点数 %d占位十进制整数
#decr2 = '我毕业于%s,毕业时间%i年的%f号'%(school,year,day) # 我毕业于德州学院,毕业时间2020年的6.200000号
decr2 = '我毕业于%s,毕业时间%i年的%d号'%(school,year,day) # 我毕业于德州学院,毕业时间2020年的6号
# 写法3:f-string
decr3 = f'我毕业于{school},毕业时间{year}年的{day}号' # 我毕业于德州学院,毕业时间2020年的6.2号
占位符精度控制 %m.nf
m
- 最小宽度,位数不够会使用空格补全,位数小于整数位数,则自动失效
- 正数是右对齐,负数是左对齐
n
- 精度控制,含义:最少用n位显示数字。
- 位数不够用0来补,位数小于整数位,则自动失效。
name = '李四'
age = 18
height = 188.45
info = '我是%4s,今年%-3i,身高%2.2f'%(name,age,height) # 我是 李四,今年18 ,身高188.45
# 写法
info2 = f'{height:.2f}'
转义字符
# 使用 \
print('输出一个'字符')
print('输出一个"字符')
# 使用\n换行
print('你好\n你也好')
# 使用\ 输出 \
print('D:\file')
# 使用\b删除前一个字符
print('helloo\b')
# \r 使光标回到本行开头,覆盖输出
print('10%\r20%')
# \t 表示水平制表符,让光标跳转到下一个制表位
print('1234123412341234')
print('ab\tcd')
print('abc\td')
print('abcd\ta')
print('显示\t中文')
"""
1234123412341234
ab cd
abc d
abcd a
显示 中文
"""
布尔类型 boolean
只用两个值 True 和 False
a = True
b = False
c = 1 > 2
print(type(a), a) # <class 'bool'>
print(type(b), b) # <class 'bool'> False
print(type(c), c) # <class 'bool'> False
boolean值本质是int的子类型,底层是用1表示True,用0表示False
print(int(True), int(False)) # 1 0
数据类型转换
str() 把数据转为字符串
result = str(10)
result2 = str(10.11)
result3 = str(1.1e3)
result4 = str(10_101)
print(type(result), result) # <class 'str'> 10
print(type(result2), result2) # <class 'str'> 10.11
print(type(result3), result3) # <class 'str'> 1100.0
print(type(result4), result4) # <class 'str'> 10101
int() 把数据转为整型
result = int(10)
result2 = int('10')
result3 = int(10.99)
result4 = int(' 10 ')
print(type(result), result) # <class 'int'> 10
print(type(result2), result2) # <class 'int'> 10
print(type(result3), result3) # <class 'int'> 10
print(type(result4), result4) # <class 'int'> 10
无效:
- int(' 1 0 ') 中间有空格
- int('中文') 中文
- int('10天')
- int('1.2')
float() 把数据转为浮点型
result = float(10)
result2 = float('20.2')
result3 = float(' 30.3 ')
result4 = float(40.4)
result5 = float('40')
print(type(result), result) # <class 'float'> 10.0
print(type(result2), result2) # <class 'float'> 20.2
print(type(result3), result3) # <class 'float'> 30.3
print(type(result4), result4) # <class 'float'> 40.4
print(type(result5), result5) # <class 'float'> 40.0
无效:
- int(' 1. 0 ') 中间有空格
- int('中文') 中文
- int('10天')
- int('1.2.3')
bool()将数据转为布尔类型
# 使用
print(bool(1), bool(0), bool('1'), bool(''))
# True False True False
六、运算符
1、算术运算符
| 运算符 | 说明 | 示例 | 结果 |
|---|---|---|---|
| + | 加 | 1 + 2 | 3 |
| - | 减 | 2 - 1 | 1 |
| * | 乘 | 1 * 2 | 2 |
| / | 除 | 3 / 2 | 1.5 |
| // | 取整 | 3 / 2 | 1 |
| % | 取余 | 8 / 5 | 3 |
| ** | 指数 | 2 ** 3 | 8 |
2、赋值与复合赋值运算符
| 运算符 | 说明 | 示例 | |
|---|---|---|---|
| = | 赋值运算 | name = '李四' | |
| += | 加法赋值运算 | num += 2 | num = num + 2 |
| -= | 减法赋值运算 | num -= 2 | num = num - 2 |
| *= | 乘法赋值运算 | num *= 2 | num = num * 2 |
| /= | 除法赋值运算 | num /= 2 | num = num / 2 |
| //= | 取整赋值运算 | num //= 2 | num = num // 2 |
| %= | 取余赋值运算 | num %= 2 | num = num % 2 |
| **= | 指数赋值运算 | num **= 2 | num = num ** 2 |
3、比较运算符
| 运算符 | 作用 | |
|---|---|---|
| == | 比较左右两侧是否相等 | |
| != | 比较左右两侧是否不相等 | |
| > | 比较左侧是否大于右侧 | 同类型比较 |
| < | 比较左侧是否小于右侧 | |
| >= | 比较左侧是否大于等于右侧 | |
| <= | 比较左侧是否小于等于右侧 |
注:
- 比较结果True or False,首字母是大写的
- 字符串进行比较时,是依次比较每个字符的Unicode编码
- 使用 ord() 查看字符Unicode编码,使用 chr() 将Unicode码转为字符
4、逻辑运算符
| 运算符 | 名称 | 说明 |
|---|---|---|
| and | 逻辑与 | 判断两侧的值,是否都为True |
| or | 逻辑或 | 判断两侧的值,是否至少有一个为True |
| not | 逻辑非 | 对值取反 |
and
- and 返回的不一定是布尔值,而是某个参与计算的值本身
- and 会先看左边,若左边是“假”,则直接返回左边,否则返回右边
- 若参与and运算的值不是布尔值,会自动转为布尔值,再进行逻辑与判断
print(True and True) # True
print(True and False) # False
print(False and True) # False
print(False and False) # False
print(2 > 1 and 2 > 0)
# # print(3/2 and 3 / 0)
print(1 - 1 and True) # 0
print('' and True) #
print(True and 2 - 1) # 1
print(1 + 2 and 2 * 1) # 2
or
- or 返回的不一定是布尔值,而是参与计算的值本身
- or 会先看左边,若左边是“真”,则直接返回左边,否则返回右边
- 若参与or运算的值不是布尔值,会自动转为布尔值,再进行逻辑判断
print(True or True) # True
print(True or False) # True
print(False or True) # True
print(False or False)# False
print(2 - 1 or False) # 1
print('你好' or '您好') # 你好
print(False or 2 / 1) # 2.0
print(1 + 2 or 2 * 1) # 3
not
- 若参与not运算的值不是布尔值,会转为布尔值,再进行逻辑判断
- not返回的值一定是布尔值
print(not True) # False
print(not False) # True
print(not 2 > 1) # False
print(not 2 < 1) # True
print(not 0) # True
七、进制
- 0b开头表示二进制
- 0o开头表示八进制
- 0x开头表示十六进制
# 0b开头表示二进制
num = 0b11001
# 0o开头表示八进制
num2 = 0o1034
# 0x开头表示十六进制
num3 = 0x1cf
Python中所有的非十进制数字,只是代码层面的编写方式,计算时会自动将其转为十进制
# Python中所有的非十进制数字,只是代码层面的编写方式,计算时会自动将其转为十进制
print(num, num2, num3) # 25 540 463
print(num + 1) # 26
print(num2 > 1) # True
print(str(num3)) # 463
Python中的进制转换
| 方法 | 说明 | 示例 |
|---|---|---|
| bin() | 十进制转二进制字符串 | bin(25) => '0b11001' |
| oct() | 十进制转八进制字符串 | bin(540) => '0o1034' |
| hex() | 十进制转十六进制字符串 | hex(463) => '0x1cf' |
| int() | 其他进制转十进制 | int('0b11001', 2) => 25 |
| int('0o1034', 8) => 540 | ||
| int('0x1cf', 16) => 463 |
八、输入语句
input() 用于获取用户的输入
input()获取到的内容全是字符串类型
name = input('请输入你的名字:')
age = input('请输入你的年龄:')
# 将age转为整型
age = int(age)
print(f'你的名字是{name},今年{age + 1}岁。')
九、流程控制语句
单分支 if
num = int(input('请输入数字:'))
if num >= 18:
print('输入的数字大于等于18')
双分支 if else
if num > 18:
print('输入的数字大')
else:
print('输入的数字小')
多分支 if elif if
if num > 18:
print('输入的数字大')
elif num < 18:
print('输入的数字小')
else:
print('相等')
嵌套分支
if xxx:
xxx
if xxx:
xxx
elif xxx:
xxx
else:
xxx
else:
xxx
while 循环
n = 1
while n <= 10:
print(f'第{n}次')
n += 1
练习
print('请输入正确密码,才能登录!')
text = '请输入密码!'
password = '123'
inputPassword = ''
while inputPassword != password:
print(f'{text}')
inputPassword = input('密码:')
if inputPassword == password:
print('密码正确')
else:
print('密码错误')
for 循环
遍历range()范围内的数字
# range(10)的范围即[0, 10),为左闭右开
for n in range(10):
print(n) # 0 1 2 3 4 5 6 7 8 9
for n in range(1, 10):
print(n) # 1 2 3 4 5 6 7 8 9
遍历字符串
for n in 'abcdef':
print(n) # a b c d e f
练习:加解密
# 练习1:
text = input('请输入要加密的文字:')
secret = ''
for char in text:
secret += chr(ord(char) + 1)
print(f'最终加密后:{secret}')
# 练习2:
secret = input('请输入要解密的文字:')
text = ''
for char in secret:
text += chr(ord(char) - 1)
print(f'最终解密后:{text}')
练习:九九乘法表
while n <= 9:
m = 1
while m <= n:
print(f'{m} * {n} = {n * m}', end='\t')
if m == n:
print('')
m += 1
n += 1
print('', end ='') 可使输出不换行
continue与break
- continue 跳出本次循环剩余语句,进入下一次循环
- break 终止循环,不再执行剩余循环
- 两者在while和for循环中均可使用,作用一样
- 两者在嵌套循环中,只能作用在其所在的循环
for m in range(1, 11):
print(f'第{m}次')
continue
print('你好')
for m in range(1, 11):
print(f'第{m}次')
if m == 2:
continue
print('你好')
for m in range(1, 11):
print(f'第{m}次')
break
print('你好')
for m in range(1, 11):
print(f'第{m}次')
if m == 2:
break
print('你好')
十、函数
内置函数:docs.python.org/zh-cn/3.13/…
内置模块:docs.python.org/zh-cn/3.13/…
语法:
# 定义
def 函数名():
函数体
# 调用
函数名()
def say():
print('你好')
say()
参数:
位置参数:
def 函数名(参数1, 参数2...)
def say(name, content):
print(f'{name}说{content}')
say('李四', 'nice to meet you')
say('张三','你好')
关键字参数:
调用时 函数名(形参名=值):
def say(name, age, gender, height):
print(f'我是{name},年龄{age},性别{gender},身高{height}')
say(name='王五', age=18, gender='男', height=188)
# 位置参数需在关键字参数之前使用
say('赵六', 20, gender='女', height=190)
- 位置参数需在关键字参数之前使用
限制传参方式:
- / 前面只能用位置参数,* 后面只能用关键字参数
- / 和 * 同时使用时, / 只能在 * 前面
def say(name, /, age, *, gender, height):
print(f'我是{name},年龄{age},性别{gender},身高{height}')
say('tom', 18, gender='男', height=190)
参数默认值
- 语法
def func(参数名=值) - 形参使用了默认值,该形参后面的参数也要有默认值
def say(name, age, gender='男', height=180):
print(f'我是{name},年龄{age},性别{gender},身高{height}')
say('tom', 18)
可变参数
定义函数时,在形参前加 * ,可接受任意数量的位置参数,并打包成一个元组
def func(*args):
print(args)
func(1, 2, 3) # (1, 2, 3)
定义函数时,在形参前加 ** ,可接受任意数量的关键字参数,并打包成一个字典
def func(**kwargs):
print(kwargs)
func(name='李四', age=19, height=76, weight=90)
# {'name': '李四', 'age': 19, 'height': 76, 'weight': 90}
NoneType 类型:None
- None是一个特殊的字面量,它表示:空值/无值/无意义
- None的类型是NoneType。
- None转为布尔值是False。
- None不能参与数学运算,也不能与字符串拼接。
- 不给函数设置返回值,函数会默认返回None。
name = None
print(type(name)) # <class 'NoneType'>
nameC = bool(name)
print(nameC) # False
返回值
使用关键字 return,得到函数返回值
def add(n, m):
return n+m
res = add(1,2)
print(res)
作用域
全局和局部
在局部作用域中可使用global声明变量是全局变量
n = 1
def add():
global n
n = 100
m = n + 1
print(m)
add()
add()
print(n)
十一、列表
数据容器:一种能存放多个数据的数据类型
定义列表
定义一个列表[元素1, 元素2, 元素3, 元素4...]
list1 = [1, 2, 3, 4, 5]
list2 = ['a', 'b', 'c', 'd', 'e']
list3 = [1, True, 'a']
list4 = [1,False,'b', [2,4,6]]
# 定义空列表
list5 = []
list6 = list()
print(list1, type(list1)) # [1, 2, 3, 4, 5] <class 'list'>
print(list2, type(list2))
print(list3, type(list3))
print(list4, type(list4))
print(list5, type(list5)) # [] <class 'list'>
print(list6, type(list6))
列表添加元素的方法
| 方法 | 说明 |
|---|---|
| append() | 向列表尾部追加一个元素 |
| insert() | 在指定下标处,插入一个元素 |
| extend() | 将可迭代对象中的内容依次取出,追加至列表尾部 |
list1 = [1,2,3]
# append() 尾部追加一个元素
list1.append(6)
print(list1)
# insert() 在指定下标处,插入一个元素
list2 = [1, 2, 3]
list2.insert(2,4)
print(list2)
# extend() 将可迭代对象中的内容依次取出,追加至列表尾部
list1.extend('星期五')
list1.extend(range(1,4))
print(list1)
列表删除元素的方法
| 方法 | 说明 |
|---|---|
| pop() | 删除指定位置元素,并返回该元素 |
| remove() | 移除首次出现的元素 |
| clear() | 清空所有元素 |
| del | 删除指定元素 |
# pop() 删除指定位置元素,并返回该元素
list1 = [1,2,3]
res = list1.pop(1)
print(res, list1)
# remove() 移除首次出现的元素
list2 = [1,2,3,1]
list2.remove(1)
print(list2)
# clear() 清空所有元素
list2.clear()
print(list2)
# del 删除指定元素
list3 = [1,2,3,4]
del list3[1]
print(list3)
列表修改元素的方法 列表名[下标] = 值
列表查询元素的方法 列表名[下标]
常用方法
| 方法 | 说明 | |
|---|---|---|
| index() | 返回元素首次出现的下标 | |
| count() | 返回元素出现的次数 | |
| reverse() | 反转列表 | 无返回值 |
| sort(reverse=True/False) | 排序列表 | 无返回值 |
list1 = ['a', 'b', 'c', 'a']
# index() 返回元素首次出现的下标
res1 = list1.index('a')
print(res1)
# count() 返回元素出现的次数
res2 = list1.count('a')
print(res2)
# reverse() 反转列表元素,无返回值
list1.reverse()
print(list1)
# sort() 排序列表,无返回值
list1.sort(reverse=False) # reverse=True/False 可控制是否排序
print(list1)
常用内置函数
| 方法 | 说明 | |
|---|---|---|
| sorted(容器, reverse=True/False) | 排序 | 返回排序后的容器 |
| max() | 找出最大值 | 返回最大值 |
| min() | 找出最小值 | 返回最小值 |
| len() | 获取容器中元素总数 | 返回元素总数 |
| sum() | 对容器元素求和<字符串不能使用sum> | 返回元素总和 |
list1 = [4, 5, 7, 1, 2, 3, 8, 6]
# sorted() 对容器进行排序
res1 = sorted(list1)
print(res1)
print(list1)
# max() 找出最大值
res2 = max(list1)
print(res2)
# min() 找出最小值
res3 = min(list1)
print(res3)
# len() 获取元素总数
res4 = len(list1)
print(res4)
# sum() 对容器元素求和<字符串不能使用sum>
res5 = sum(list1)
print(res5)
循环遍历
- 通过
for item in list1:获取每项元素item for index in range(len(list1)):获取到元素下标indexfor index, item in enumerate(list1, start=5):获取到元素下标index和元素item,参数start可让计数从指定值开始
十二、元组
- 元组是和列表类似的数据容器,区别是元组中的元素不可修改
- 元组中存在可变类型(列表),那可变类型中的元素可修改
定义一个元组(元素1, 元素2, 元素3, 元素4...)
定义空元组
t1 = ()
t2 = tuple()
定义只有一个元素的元组:元素后须跟逗号
t1 = ('a',)
t2 = (1,)
# 定义元组
t1 = (1, 2, 3, 4, 5)
t2= ('a', 'b', 'c', 'd', 'e')
t3 = (1,True,'哈哈', (30,230,239))
# 元组下标
print(t1[1])
print(t2[-1])
print(t3[2])
print(t3[3][0])
# 元组中存在可变类型(列表),那可变类型中的元素可修改
t4 = (1,2,3,4, [5,6,7,8, ('你好', 'hh')])
# t4[0] = 10 X
# t4[4] = 100 X
t4[4][1] = 55
# t4[4][1][0] = 22 X
print(t4)
常用方法
| 方法 | 说明 | |
|---|---|---|
| index() | 返回元素首次出现的下标 | |
| count() | 返回元素出现的次数 |
t1 = (1,2,2,4,5,2)
print(t1.index(2)) # 1
print(t1.count(2)) # 3
常用内置函数
| 方法 | 说明 | |
|---|---|---|
| sorted(容器, reverse=True/False) | 排序 | 返回排序后的容器 |
| max() | 找出最大值 | 返回最大值 |
| min() | 找出最小值 | 返回最小值 |
| len() | 获取元组中元素总数 | 返回元组长度 |
| sum() | 对元组元素求和<字符串不能使用sum> | 返回元素总和 |
t1 = (1, 2, 2, 4, 5, 2)
print(max(t1)) # 5
print(min(t1)) # 1
print(len(t1)) # 6
print(sorted(t1)) # [1, 2, 2, 2, 4, 5]
print(sum(t1)) # 16
使用*对解包列表或元组
def test(*args):
print(args)
tt1 = (1,2,3,4,5,6)
tt2 = ('a','b','c','d','e','f')
test(*tt1) # 相当于test(1,2,3,4,5,6)
test(*tt2)
十三、字符串 str
- 字符串同样有下标
- 字符串中的字符不可修改
- 字符串不能嵌套
常用方法
| 方法 | 说明 | |
|---|---|---|
| index() | 返回字符首次出现的下标 | |
| split() | 按照指定字符分割,组成新列表 | |
| replace() | 将某个字符替换成目标字符 | |
| count() | 返回字符出现的次数 | |
| strip() | 删除指定字符串中的任意字符 |
- strip() 从字符两端开始删除,直到遇到第一个不在字符串中的字符就停止
str1 = 'welcome to python'
print(str1[1])
# str1[1] = '2' # X
print(str1.index('e')) # 1
print(str1.split(' ')) # ['welcome', 'to', 'python']
print(str1.replace('e','*')) # w*lcom* to python
print(str1.count('e')) # 2
# strip() 从字符两端开始删除,直到遇到第一个不在字符串中的字符就停止
str3 = '111we1l1come111'
res = str3.strip('1')
print(res) # we1l1come
str4 = '1234py32thon1342'
res2 = str4.strip('1234')
print(res2) # py32thon
str5 = '12534py32thon16342'
res5 = str5.strip('321')
print(res5) # 534py32thon1634
# strip()不传参数,用于去两端空格
str6 = ' python '
res6 = str6.strip()
print(res6) # python
常用内置函数
| 方法 | 说明 |
|---|---|
| len() | 统计字符串中字符的个数 |
| max() | 找出字符串中unicode编码值最大的字符 |
| min() | 找出字符串中unicode编码值最小的字符 |
| sorted() | 按照unicode值排序 |
序列的切片操作
- 序列:能连续存放元素的数据容器,元素有先后顺序,可通过下标访问,列表、元组、字符串都是序列
- 切片:从序列中按照指定范围,取出一部分元素,形成一个新序列的操作
语法:[起始索引:结束索引:步长]
默认起始索引为0,结束索引截取到末尾,步长为1
起始索引大于结束索引时,步长需为负数
list1 = [10, 20, 30, 40, 50, 60, 70, 80, 90]
res1 = list1[1:5:1] # [20, 30, 40, 50]
res2 = list1[2:8:2] # [30, 50, 70]
res3 = list1[::] # [10, 20, 30, 40, 50, 60, 70, 80, 90]
res4 = list1[5:2:-1] # [60, 50, 40]
res = list1[::-1] # [90, 80, 70, 60, 50, 40, 30, 20, 10]
相加:新序列 = 序列1 + 序列2 同类型的才能相加
list2 = [1,2,3]
list3 = [4,5,6]
res23 = list2 + list3 # [1, 2, 3, 4, 5, 6]
t1 = ('a','b','c')
t2 = ('c','b','a')
t12 = t1 + t2 # ('a', 'b', 'c', 'c', 'b', 'a')
str1 = 'hello'
str2 = ' world'
str3 = str1 + str2 # hello world
相乘(重复)新序列 = 序列 * n n必须为整数
list2 = [1,2,3]
t1 = ('a','b','c')
str1 = 'hello'
print(list2*2) # [1, 2, 3, 1, 2, 3]
print(t1*2) # ('a', 'b', 'c', 'a', 'b', 'c')
print(str1*2) # hellohello
十四、集合
集合内部元素无序,不能通过下标访问元素,会自动去重
set()
可变集合:创建后可以增删元素 {元素0, 元素1, 元素3...}
s1 = {10, True, 1, '你好'}
s2 = {1, 2, 3, 1, 3, 4, 5}
s3 = {'a', 'b', 'c', 'a', 'd'}
print(s1, type(s1)) # {True, 10, '你好'} <class 'set'>
print(s2, type(s2)) # {1, 2, 3, 4, 5} <class 'set'>
print(s3, type(s3)) # {'c', 'b', 'a', 'd'} <class 'set'>
定义空集合 s1 = set()。
不可定义s1 = {},因为直接写{}定义的是空字典
frozenset()
不可变集合:创建后不可增删元素 frozenset({元素0, 元素1, 元素3...})
s1 = frozenset({10, True, 1, '你好'})
s2 = frozenset({1, 2, 3, 1, 3, 4, 5})
s3 = frozenset({'a', 'b', 'c', 'a', 'd'})
print(s1, type(s1)) # frozenset({True, 10, '你好'}) <class 'frozenset'>
print(s2, type(s2)) # frozenset({1, 2, 3, 4, 5}) <class 'frozenset'>
print(s3, type(s3)) # frozenset({'d', 'c', 'a', 'b'}) <class 'frozenset'>
frozenset接收的参数,可以是任意可迭代参数,但最终返回的一定是【不可变集合】
s1 = frozenset(['a', 'b', 'c', 'd'])
s2 = frozenset(['a', 'b', 'c', 'd'])
s3 = frozenset('hello')
print(s1, type(s1)) # frozenset({'b', 'c', 'd', 'a'}) <class 'frozenset'>
print(s2, type(s2)) # frozenset({'b', 'c', 'd', 'a'}) <class 'frozenset'>
print(s3, type(s3)) # frozenset({'o', 'e', 'h', 'l'}) <class 'frozenset'>
定义空集合 s1 = frozenset()
集合中不可嵌套【可变集合】,但可以嵌套【不可变集合】
s1 = {1, 2, 3, 4, 5}
s2 = frozenset({10, 20, 30, 40, 50})
l1 = [100, 200, 300, 400, 500]
t1 = (11, 22, 33, 44, 55)
# s3 = {66, 77, 88, s1} # 报错
s3 = {66, 77, 88, s2} # 运行正常
# s4 = {6, 7, 8, l1} # 报错
s4 = {6, 7, 8, t1} # 运行正常
集合的增删改
增:add()、update()
# add() 方法向集合中添加元素
s1.add(4)
s1.add(5)
print(s1)
# update() 方法向集合中添加元素(必须传递可迭代对象,列表、元组、集合等)
s1.update([10, 20, 30])
s1.update((40, 50))
s1.update({60, 70, 80})
s1.update(range(100, 105))
print(s1)
删:remove()、discard()、pop()、clear()
s1 = {1, 2, 3, 4, 5}
# remove() 从集合中移除指定元素,若不存在,会报错,无返回值
# s1.remove(1)
# discard() 从集合中移除指定元素,若不存在,不会报错,无返回值
# s1.discard(5)
# pop() 从集合中移除任意一个元素(随机),返回移除的元素
res = s1.pop()
# clear() 清空集合
s1.clear()
print(res, s1)
集合没有下标,也不支持切片操作
改:
可通过remove和add达到修改操作
s1 = {1, 2, 3, 4, 5}
s1.remove(4)
s1.add(6)
查:
可通过【成员运算符】in或not in去查看集合中是否有某个元素
s1 = {1, 2, 3, 4, 5}
res = 1 in s1
res2 = 1 not in s1
print(res, res2)
常用方法
difference()
a = {1, 2, 3, 5}
b = {4, 5, 6, 1}
# difference找出集合a中不同于集合b的元素,集合a和集合b都不变,返回一个新集合
res = a.difference(b)
print(a) # {1, 2, 3, 5}
print(b) # {1, 4, 5, 6}
print(res) # {2, 3}
difference_update()
a = {1, 2, 3, 5}
b = {4, 5, 6, 1}
# difference_update 从集合a中,删除b中存在的元素,集合a会被修改,b不会,无返回值
a.difference_update(b)
print(a) # {2, 3}
print(b) # {1, 4, 5, 6}
union()
a = {1, 2, 3, 5}
b = {4, 5, 6, 1}
# 合并两个集合,集合a、b都不变,返回一个新集合
res = a.union(b)
print(a) # {1, 2, 3, 5}
print(b) # {1, 4, 5, 6}
print(res) # {1, 2, 3, 4, 5, 6}
issubset()、issuperset()、isdisjoint()
a = {1, 2, 3}
b = {1, 2, 3, 4, 5, 6}
c = {4, 5, 6, 7, 8, 9}
# 判断集合a是否是集合b的子集,返回布尔值
print(a.issubset(b)) # True
print(c.issubset(b)) # False
# 判断集合a是否是集合b的超集,返回布尔值
print(b.issuperset(a)) # True
print(c.issuperset(b)) # False
# 判断集合a和集合b是否没有交集,返回布尔值
print(a.isdisjoint(b)) # False
print(a.isdisjoint(c)) # True
集合中的数学运算
并集 集合a | 集合b
a = {1, 2, 3, 4, 5, 6}
b = {4, 5, 6, 7, 8, 9}
# 并集:合并集合的元素
res = a | b # {1, 2, 3, 4, 5, 6, 7, 8, 9}
交集 集合a & 集合b
# 交集:找出集合中共有的元素
# res = a & b # {4, 5, 6}
差集 集合a - 集合b
# 差集 去除集合a中,集合b中也有的元素
# res = a - b # {1, 2, 3}
对称差集 集合a ^ 集合b
# 对称差集 在并集中去除掉交集
# res = a ^ b # {1, 2, 3, 7, 8, 9}
集合的循环遍历
集合没有下标,所以不能使用while,但可以使用for
b = {4, 5, 6, 7, 8, 9}
# 循环遍历
for item in b:
print(item)
# 集合没有下标 不能使用while
# index = 0
# while index < len(b):
# print(b[index])
十五、字典
定义字典 {key: value}
d1 = {'张三': 11, '李四': 2, '王五': 3, 'tom': 4}
print(d1, type(d1)) # {'张三': 11, '李四': 2, '王五': 3, 'tom': 4} <class 'dict'>
# 定义空字典
d2 = {}
d3 = dict()
字典key不能重复
# 字典的key不能重复,若出现重复,后者会覆盖前者
d1 = {'张三': 11, '李四': 2, '王五': 3, 'tom': 4, '张三': 22}
print(d1)
key必须是不可变类型,但value可为任意类型
# key必须是不可变类型,但value可为任意类型
d1 = {12: 12, '李四': 22}
d2 = {('你好', 'python'): 12, '李四': 22}
d3 = {['你好', 'python']: 23} # 报错
字典可以嵌套
# 字典嵌套
d1 = {
2001: {'张三': 11, '李四': 2, '王五': 3, 'tom': 4},
2002: {'张三': 12, '李四': 22, '王五': 3, 'tom': 4},
2003: {'张三': 13, '李四': 23, '王五': 3, 'tom': 4},
}
字典增删改查
</tbody>
| 操作 | 写法 | 说明 | 返回值 |
|---|---|---|---|
| 新增 | 字典[key] = 值 | 新增一组键值对(若键已存在则变为修改) | 无 |
| 删除 | |||
| del 字典[key] | 删除指定键对应的键值对(键不存在会报错) | 无 | |
| 字典.pop(key, 默认值) | 删除指定键对应的键值对 | 返回被删除键的值或默认值 | |
| 字典.clear() | 删除所有键值对 | 无 | |
| 修改 | |||
| 字典[key] = 值 | 修改指定键对应的键值对(键不存在则为新增) | 无 | |
| 字典.update(其他字典) | 批量修改或合并多个键值对 | 无 | |
| 查询 | |||
| 字典[key] | 根据键取值(键不存在会报错) | 键对应的值 | |
| 字典.get(key, 默认值) | 安全取值,键不存在则返回默认值,未设置默认值返回None | 键对应的值或默认值 |
常用方法
| 方法 | 说明 | 返回值类型 |
|---|---|---|
| 字典.keys() | 获取所有的键 | 'dict_keys' |
| 字典.values() | 获取所有的值 | 'dict_values' |
| 字典.items() | 获取所有的键值对 | 'dict_items' |
dict1 = {'a': 1, 'b': 2, 'c': 3, }
# keys:获取字典中所有的键
res = dict1.keys() # dict_keys(['a', 'b', 'c']) <class 'dict_keys'>
# dict_keys和列表相似,可以遍历,但不能用下标访问
for item in res:
print(item, end='\t')
# print(res[0])
# 借助内置函数list函数,可将dict_keys转为list
res_list = list(res) # ['a', 'b', 'c'] <class 'list'>
# values: 获取字典中所有的值
res = dict1.values() # dict_values([1, 2, 3]) <class 'dict_values'>
# items: 用于获取字典中所有键值对
res = dict1.items() # dict_items([('a', 1), ('b', 2), ('c', 3)]) <class 'dict_items'>
十六、类
定义一个类
类名通常使用大驼峰写法
- 当一个函数被定义在了类中时,那这个函数就被称为:方法
- init 方法:初始化方法,是给当前正在创建的实例对象添加属性
- init 方法接收到的参数:当前正在创建的实例对象(self)、其他的自定义参数
- 当创建Person类实例的时候,Python会自动调用__init__
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 创建实例对象
p1 = Person('张三', 19)
实例属性
- 给实例添加属性(语法为:self.属性名 = 值 )
- 通过实例.属性名 = 值 给实例添加的属性,就是实例属性
- 实例属性只能通过实例访问,不能通过类访问,每个实例间的实例属性都是互不干扰的
通过 实例.dict 可以查看实例上的所有属性
# print(p1.__dict__)
# {'name': '张三', 'age': 18, 'gender': 'male'}
类属性
- 类属性可以通过类访问,也可以通过实例访问
- 类属性通常用于保存 公共数据
class Person:
# 类属性
max_age = 120
min_age = 90
def __init__(self, name, age):
self.name = name
if age > Person.max_age:
self.age = Person.max_age
else:
self.age = age
# 类属性
p1 = Person('张三', 910)
# p1.speak('哈哈哈')
# 类属性是存在类身上的,实例上是没有的
print(p1.__dict__)
# {'name': '张三', 'age': 120}
print(Person.__dict__)
# {'__module__': '__main__', '__firstlineno__': 2, 'max_age': 120, 'min_age': 90, '__init__': <function Person.__init__ at 0x0000021FF0966610>, 'speak': <function Person.speak at 0x0000021FF0966820>, '__static_attributes__': ('age', 'name'), '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
# 类属性可以通过类访问,也可通过实例访问
print(Person.min_age)
print(p1.min_age) # 查找min_age的过程:1、实例自身(p1) => 2、实例的缔造者(Person)
自定义方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self, words):
print(f'我是{self.name},年龄{self.age},说了{words}')
p2 = Person('李四', 22)
# speak 方法是存在Person类身上的,Person的实例对象上是没有speak方法的
# p2.speak('侬好!')
print(p2.__dict__)
# {'name': '李四', 'age': 22}
print(Person.__dict__)
# {'__module__': '__main__', '__firstlineno__': 2, '__init__': <function Person.__init__ at 0x0000024F783A6610>, 'speak': <function Person.speak at 0x0000024F783A6820>, '__static_attributes__': ('age', 'name'), '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
# 当执行p2.speak()时,查找speak的过程:1.实例对象自身(p2) => 2.实例的缔造者身上(Person)
def speak():
print('你好~')
p2.speak = speak
p2.speak()
# 你好~
实例方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# speak、run方法都存在类身上,主要是供实例使用,即实例方法
def speak(self, msg):
print(f'我是{self.name},年龄{self.age},说了{msg}')
def run(self, km):
print(f'{self.name}距离还有{km}')
# 创建实例
p1 = Person('张三', 88)
# 通过实例调用实例方法
p1.run(100)
# 通过类调用实例方法
Person.run(p1,200)
类方法
- 通过@classmethod装饰过的方法就是类方法,类方法是保存在类身上的
- 类方法收到的参数:当前类本身cls、自定义的参数
- cls:就可访问类属性
- 类方法通常用于实现与类相关的逻辑:操作类级别的信息,一些工厂函数
from datetime import datetime
class Person:
max_age = 120
def __init__(self, name, age):
self.name = name
self.age = age
# 实例方法
def speak(self, msg):
print(f'我是{self.name},年龄{self.age},说了{msg}')
def run(self, km):
print(f'{self.name}距离还有{km}')
# 类方法
@classmethod
def test(cls, data):
print(f'这里是类方法{data}')
@classmethod
def get_age(cls, value):
print(cls, cls.max_age) # <class '__main__.Person'> 120
current_year = datetime.now().year
age = current_year - value
return age
p1 = Person('张三', 88)
# 类方法是存在类身上的
# print(Person.__dict__)
# 类方法要通过类调用
# Person.test(100)
res = Person.get_age(1997)
print(res)
静态方法
- 使用 @staticmethod 装饰过的方法,就叫:静态方法,静态方法也是保存在类身上的
- 静态方法只是单纯的定义在类中,它不会收到:self、cls它收到的参数都是自定义参数
- 由于静态方法没有收到:self、cls参数,所以其内部不会访问任何:类和实例相关的内容
- 静态方法常用于定义:与类相关的工具方法
from datetime import datetime
class Person:
age_limit = 18
def __init__(self, name, age):
self.name = name
self.age = age
@staticmethod
def is_adult(year):
current_year = datetime.now().year
age = current_year - year
return age >= 18
# 静态方法是存在类身上的
print(Person.__dict__)
# {'__module__': '__main__', '__firstlineno__': 3, 'age_limit': 18, '__init__': <function Person.__init__ at 0x000001E1C4D06610>, 'is_adult': <staticmethod(<function Person.is_adult at 0x000001E1C4D06820>)>, '__static_attributes__': ('age', 'name'), '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
# 静态方法要通过类去调用
res = Person.is_adult(2015)
print(res)
继承
定义一个Student类(子类、派生类),继承自Person类(父类、超类、基类) class Student(Person):
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self, words):
print(f'{self.name} is {self.age} years old, said {words}')
# 定义一个Student类(子类、派生类),继承自Person类(父类、超类、基类)
class Student(Person):
pass
# 创建Student类的实例
s1 = Student('李四', 18)
print(s1.name)
print(s1.age)
# 查找speak的过程:1、实例自身(s1) => 2、Student类 => 3、Person类
s1.speak('hello')
在子类中,有两种方式去调用父类的初始化方法,来实现对继承属性name,age的初始化
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 定义一个Student类
class Student(Person):
def __init__(self, name, age, stu_id, stu_grade):
# 方式一
super().__init__(name, age)
# 方式二
Person.__init__(self, name, age)
# 子类独有的属性 需自己初始化
self.stu_id = stu_id
self.stu_grade = stu_grade
def study(self ):
print(f'我叫{self.name},现在{self.stu_grade}年级')
# 创建Student类的实例
s1 = Student('李四', 18, 1001, 2)
# 查找study的过程:1、实例自身(s1) => 2、Student类 => 3、Person类
s1.study()
方法重写
当子类中定义一个与父类中相同的方法,那子类中的方法就会“重写”父类中的方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self, words):
print(f'{self.name} is {self.age} years old, said {words}')
# 定义一个子类继承父类
class Student(Person):
def __init__(self, name, age, stu_id, stu_grade):
super().__init__(name, age)
self.stu_id = stu_id
self.stu_grade = stu_grade
# 方法重写
def speak(self, words):
# 调用父类
super().speak(words)
print(f'学号是{self.stu_id},今年{self.stu_grade}年级,说了{words}')
# 创建实例
s1 = Student('李四',19, '10021', 3)
s1.speak('你好')
常用方法
- issubclass(Class, Class) 判断某个类是否为另一个类的子类
- isinstance(instance, Class) 判断某个对象是否为指定类或子类的实例
...
p1 = Person('张三', 28)
s1 = Student('李四',19, '10021', 3)
# isinstance
print(isinstance(p1, Person))
print(isinstance(s1, Student))
print(isinstance(s1, Person))
print(isinstance(p1, Student))
# True True True False
# issubclass
print(issubclass(Student, Person))
print(issubclass(Person, Student))
# True False
多重继承
定义一个子类,继承多个父类class Student(Person, Worker):
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self, words):
print(f'{self.name} is {self.age} years old, said {words}')
class Worker:
def __init__(self, work_name):
self.work_name = work_name
def do_work(self):
print(f'{self.work_name} is doing work')
# 定义一个子类,继承多个父类
class Student(Person, Worker):
def __init__(self, name, age, work_name, grade):
# 用类名去初始
Person.__init__(self, name, age)
Worker.__init__(self, work_name)
self.grade = grade
def study(self):
print(f'study hard,{self.grade} grade!')
s1 = Student('张三', 10, 'waiter',5)
print(s1.__dict__)
s1.speak('hello')
s1.do_work()
s1.study()
# 类的__mro__属性,用于记录属性和方法的查找顺序
# 通过实例查询属性或方法时,会现在实例自身找,若没有,再按照__mro__记录的顺序去查找
print(Student.__mro__)
# (<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Worker'>, <class 'object'>)
三种访问限制
- 共有属性
属性名当前类、子类、类外部,都能访问 - 受保护的属性
_属性名当前类、子类,都能访问 - 私有属性
__属性名仅能在当前类中访问
class Person:
def __init__(self, name, age, id_number):
self.name = name # 共有属性
self._age = age # 受保护的属性
self.__id_number = id_number # 私有属性
def speak(self):
print(f'名称:{self.name}, 年龄:{self._age}, 身份证:{self.__id_number}')
class Student(Person):
def study(self):
print(f'子类中-名称:{self.name}, 年龄:{self._age}, 身份证:{self.__id_number}')
# 当前类中访问
p1 = Person('李四', 19, '10002')
p1.speak() # 名称:李四, 年龄:19, 身份证:10002
# 子类中访问
s1 = Student('张三', 22, '10003')
# s1.study() # AttributeError: 'Student' object has no attribute '_Student__id_number'
# 在外部访问
print(p1.name) # 李四 共有属性可以正常访问
# print(p1._age) # 19 受保护的属性强制访问,可以访问,但不推荐
# print(p1.__id_number) # 私有属性访问报错 AttributeError: 'Person' object has no attribute '__id_number'
# Python底层是通过重命名实现私有属性的
print(p1.__dict__) # {'name': '李四', '_age': 19, '_Person__id_number': '10002'}
print(p1._Person__id_number) # 10002 不推荐
getter&setter
注册age属性的getter方法
@property
def age(self):
...
注册age属性的setter方法
@age.setter
def age(self,value):
...
class Person:
max_age = 120
def __init__(self, name, age, id_number):
self.name = name
self._age = age
self.__id_number = id_number
# 注册age属性的getter方法,当访问Person实例的age属性时,下面的age方法就会被自动调用
@property
def age(self):
return self._age
# 注册age属性的setter方法,当修改Person实例的age属性时,下面的age方法就会被自动调用
@age.setter
def age(self,value):
if value > self.max_age:
print('年龄超出限制')
else:
self._age = value
# 注册id_number属性的getter方法,当访问Person实例的id_number属性时,下面的id_number方法就会被自动调用
@property
def id_number(self):
return self.__id_number[:6] + '*******'+ self.__id_number[-4:]
# 注册id_number属性的setter方法,当修改Person实例的id_number属性时,下面的id_number方法就会被自动调用
@id_number.setter
def id_number(self,value):
print('身份证号不允许修改!')
p1 = Person('张三', 22, '370831199712345678')
print(p1.age)
p1.age = 130
print(p1.age)
print(p1.id_number)
p1.id_number = '10002'
print(p1.id_number)
魔法方法
以__xxx__双下划线开头和结尾命名的特殊方法
| 方法 | 调用时机 |
|---|---|
__str__ | 当调用print(对象)或str(对象)时 |
__len__ | 当调用len(对象)时 |
__gt__ | 当执行对象1>对象2时 |
__lt__ | 当执行对象1<对象2时 |
__eq__ | 当执行对象1==对象2时 |
__getattr__ | 当访问不存在属性时 |
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# 当执行 print(Person的实例对象) 或 str(Person的实例对象) 时调用
def __str__(self):
# 默认返回 <__main__.Person object at 0x0000021B2B7270E0>
# 修改返回 我是张三,今年22
return f'我是{self.name},今年{self.age},性别{self.gender}'
# 当执行 len(Person的实例对象) 时调用
def __len__(self):
return len(self.__dict__)
# 当执行 Person实例对象1 > Person实例对象2 时调用
def __gt__(self, other):
return self.age > other.age
# 当执行 Person实例对象1 < Person对象实例2 时调用
def __lt__(self, other):
return self.age < other.age
# 当执行 Person实例对象1 == Person对象实例2 时调用
def __eq__(self, other):
return self.__dict__ == other.__dict__
# 当访问不存在属性时
def __getattr__(self, item):
return f'属性{item}不存在'
p1 = Person('张三', 22, '男')
p2 = Person('李四', 23, '女')
# print(p1)
# print(str(p1))
# print(len(p1))
# res = p1 > p2
# print(res)
# res = p1 < p2
# print(res)
res = p1 == p2
print(res)
print(p1.no_name)
object类
# Python中,所有的类都继承了 object 类,即object类是所有类的顶层父类
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
# Person类继承了object类
# print(issubclass(Person, object))
# 所有的类继承了object类
# print(issubclass(int, object))
# print(issubclass(str, object))
# print(issubclass(bool, object))
# print(issubclass(list, object))
# print(issubclass(tuple, object))
# object是所有类的父类,所以所有对象,都间接是object的实例
p1 = Person('张三', 12)
# print(isinstance(p1, Person))
# print(isinstance(p1, object))
# print(isinstance(200, object))
# print(isinstance('python', object))
# print(isinstance(True, object))
# print(isinstance(None, object))
# print(isinstance([1, 2, 3], object))
# print(isinstance({'a', 'b'}, object))
# 调用对象都继承了object类所提供的 各种属性和方法,从而保证了每个对象都具备统一的基本能力
for item in object.__dict__:
print(item)
多态
- 多态:同一个方法,在不同的对象上调用时,能呈现出不同的行为
- 多态又分 标准多态、鸭子多态
标准多态
标准多态的三个条件:继承关系、方法重写、类型限制
class Animal:
def speak(self):
print('动物们的叫声')
class Dog(Animal):
def speak(self):
print('汪汪汪')
class Cat(Animal):
def speak(self):
print('喵喵喵')
class Pig:
def speak(self):
print('哼哼哼')
def make_sound(animal: Animal): # 类型注解
# 多态的体现
animal.speak()
# 创建实例
a1 = Animal()
d1 = Dog()
c1 = Cat()
p1 = Pig()
make_sound(a1)
make_sound(d1)
make_sound(c1)
make_sound(p1) # 不报错,但不推荐
鸭子多态
鸭子类型是一种编程风格,不检查对象的类型,只关注对象能否“做某件事”(是否有对应的方法)
# 鸭子多态
class Animal:
def speak(self):
print('动物们的叫声')
class Dog:
def speak(self):
print('汪汪汪')
class Cat:
def speak(self):
print('喵喵喵')
class Pig:
def speak(self):
print('哼哼哼')
def make_sound(animal):
animal.speak()
# 创建实例
a1 = Animal()
d1 = Dog()
c1 = Cat()
p1 = Pig()
make_sound(a1)
make_sound(d1)
make_sound(c1)
make_sound(p1)
抽象类
抽象类是一种不能直接实例化的类,它通常作为“规范”,让子类去继承,并实现其中定义的的抽象方法
from abc import ABC, abstractmethod
# MustRun类一旦继承就ABC类,那么MustRun类就是抽象类了
class MustRun(ABC):
@abstractmethod
def run(self):
pass
# m1 = MustRun() #无法实例化抽象类 'MustRun'
# 类 Person 必须实现所有 abstract 方法
class Person(MustRun):
def __init__(self, name):
self.name = name
def run(self):
print(f'{self.name} is running...')
p1 = Person('P1')
p1.run()