Python基础知识

前言

最近ai势头正猛,公司也是要求学习ai了!自己先从Python入手,整理了份笔记,记录一下python语法。其语法和其他语言是相通的,只是写法不同。

一、字面量

  1. 所谓字面量,就是直接写在代码中的具体值
  2. Python的字符串中可以包含任意字符,且必须使用引号包起来。
  3. 字符串的引号,可以是:单引号、双引号、三个单引号、三个双引号。
  4. 写在Python文件头部的字符串,会被自动识别成docstring(文档字符串)
  5. 文档字符串的主要作用是:对当前Python文件进行一些说明,且文档字符串必须用三个双引号
python 复制代码
"""python"""

"python"
'python'
'''python'''

二、变量

语法:变量名 = 值

python 复制代码
name = '李四'
age = 18
height = '188'
print('你好!我叫' + name, '今年', age, '岁,身高' + height + 'cm。')

三、标识符命名规则

  1. 只能包含:数字、字母、下划线,且不能以数字开头,不能包含空格
  2. 标识符区分大小写,例如 Name和name是两个不同的标识符。
  3. 标识符不能使用关键字,
  4. 标识符尽量不要与内置函数同名。
  5. 标识符虽然没有长度限制,但应追求:简洁清晰,具有描述性。
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中没有强制的常量机制,其本质还是变量,只是约定好不要去修改!

python 复制代码
# ctrl+shift+u 转换大小写
AGE = 13
NAME = 'abc'

五、数据类型

类型名称 英文名 举例 说明
字符串 string '李四' 用引号包裹
整型 int 18 没有小数的数字
浮点型 float 20.26 有小数的数字
...

type() 用来判断类型

bash 复制代码
print(type('李四')) # <class 'str'>
print(type(18)) # <class 'int'>
print(type(23.12)) # <class 'float'>

整型 int

ini 复制代码
# 整型:没有小数点的整数,可以是正数,负数,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

ini 复制代码
# 浮点型就是带有小数的数字
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

字符串拼接

ini 复制代码
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

  1. 最小宽度,位数不够会使用空格补全,位数小于整数位数,则自动失效
  2. 正数是右对齐,负数是左对齐

n

  1. 精度控制,含义:最少用n位显示数字。
  2. 位数不够用0来补,位数小于整数位,则自动失效。
ini 复制代码
name = '李四'
age  = 18
height = 188.45

info = '我是%4s,今年%-3i,身高%2.2f'%(name,age,height)  # 我是  李四,今年18 ,身高188.45

# 写法
info2 = f'{height:.2f}'

转义字符

scss 复制代码
# 使用 \
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

ini 复制代码
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

python 复制代码
print(int(True), int(False))  # 1 0

数据类型转换

str() 把数据转为字符串

python 复制代码
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() 把数据转为整型

go 复制代码
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() 把数据转为浮点型

scss 复制代码
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()将数据转为布尔类型

php 复制代码
# 使用
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、比较运算符

运算符 作用
== 比较左右两侧是否相等
!= 比较左右两侧是否不相等
> 比较左侧是否大于右侧 同类型比较
< 比较左侧是否小于右侧 同类型比较
>= 比较左侧是否大于等于右侧 同类型比较
<= 比较左侧是否小于等于右侧 同类型比较

注:

  1. 比较结果True or False,首字母是大写的
  2. 字符串进行比较时,是依次比较每个字符的Unicode编码
  3. 使用 ord() 查看字符Unicode编码,使用 chr() 将Unicode码转为字符

4、逻辑运算符

运算符 名称 说明
and 逻辑与 判断两侧的值,是否都为True
or 逻辑或 判断两侧的值,是否至少有一个为True
not 逻辑非 对值取反

and

  • and 返回的不一定是布尔值,而是某个参与计算的值本身
  • and 会先看左边,若左边是"假",则直接返回左边,否则返回右边
  • 若参与and运算的值不是布尔值,会自动转为布尔值,再进行逻辑与判断
python 复制代码
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运算的值不是布尔值,会自动转为布尔值,再进行逻辑判断
python 复制代码
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返回的值一定是布尔值
python 复制代码
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开头表示十六进制
ini 复制代码
# 0b开头表示二进制
num = 0b11001

# 0o开头表示八进制
num2 = 0o1034

# 0x开头表示十六进制
num3 = 0x1cf

Python中所有的非十进制数字,只是代码层面的编写方式,计算时会自动将其转为十进制

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() 其他进制转十进制 int('0o1034', 8) => 540
int() 其他进制转十进制 int('0x1cf', 16) => 463

八、输入语句

input() 用于获取用户的输入

input()获取到的内容全是字符串类型

python 复制代码
name = input('请输入你的名字:')
age = input('请输入你的年龄:')
# 将age转为整型
age = int(age)
print(f'你的名字是{name},今年{age + 1}岁。')

九、流程控制语句

单分支 if

dart 复制代码
num = int(input('请输入数字:'))
if num >= 18:
    print('输入的数字大于等于18')

双分支 if else

dart 复制代码
if num > 18:
    print('输入的数字大')
else:
    print('输入的数字小')

多分支 if elif if

dart 复制代码
if num > 18:
    print('输入的数字大')
elif num < 18:
    print('输入的数字小')
else:
    print('相等')

嵌套分支

yaml 复制代码
if xxx:
    xxx
    if xxx:
        xxx
    elif xxx:
        xxx
    else:
        xxx
else:
    xxx

while 循环

python 复制代码
n = 1
while n <= 10:
    print(f'第{n}次')
    n += 1

练习

python 复制代码
print('请输入正确密码,才能登录!')
text = '请输入密码!'
password = '123'
inputPassword = ''

while inputPassword != password:
    print(f'{text}')
    inputPassword = input('密码:')
    if inputPassword == password:
        print('密码正确')
    else:
        print('密码错误')

for 循环

遍历range()范围内的数字

python 复制代码
# 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

遍历字符串

bash 复制代码
for n in 'abcdef':
    print(n) # a b c d e f

练习:加解密

python 复制代码
# 练习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}')

练习:九九乘法表

python 复制代码
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循环中均可使用,作用一样
  • 两者在嵌套循环中,只能作用在其所在的循环
python 复制代码
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('你好')
python 复制代码
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/...

语法:

python 复制代码
# 定义
def 函数名():
    函数体
    
# 调用
函数名()
scss 复制代码
def say():
    print('你好')

say()

参数:

位置参数:

def 函数名(参数1, 参数2...)

python 复制代码
def say(name, content):
    print(f'{name}说{content}')

say('李四', 'nice to meet you')
say('张三','你好')

关键字参数:

调用时 函数名(形参名=值):

python 复制代码
def say(name, age, gender, height):
    print(f'我是{name},年龄{age},性别{gender},身高{height}')
    
say(name='王五', age=18, gender='男', height=188)

# 位置参数需在关键字参数之前使用
say('赵六', 20, gender='女', height=190)
  • 位置参数需在关键字参数之前使用

限制传参方式:

  • / 前面只能用位置参数,* 后面只能用关键字参数
  • / 和 * 同时使用时, / 只能在 * 前面
python 复制代码
def say(name, /, age, *, gender, height):
    print(f'我是{name},年龄{age},性别{gender},身高{height}')

say('tom', 18, gender='男', height=190)

参数默认值

  • 语法 def func(参数名=值)
  • 形参使用了默认值,该形参后面的参数也要有默认值
python 复制代码
def say(name, age, gender='男', height=180):
    print(f'我是{name},年龄{age},性别{gender},身高{height}')

say('tom', 18)

可变参数

定义函数时,在形参前加 * ,可接受任意数量的位置参数,并打包成一个元组

go 复制代码
def func(*args):
    print(args)

func(1, 2, 3)    # (1, 2, 3)

定义函数时,在形参前加 ** ,可接受任意数量的关键字参数,并打包成一个字典

go 复制代码
def func(**kwargs):
    print(kwargs)

func(name='李四', age=19, height=76, weight=90)   
# {'name': '李四', 'age': 19, 'height': 76, 'weight': 90}

NoneType 类型:None

  1. None是一个特殊的字面量,它表示:空值/无值/无意义
  2. None的类型是NoneType。
  3. None转为布尔值是False。
  4. None不能参与数学运算,也不能与字符串拼接。
  5. 不给函数设置返回值,函数会默认返回None。
python 复制代码
name = None

print(type(name))  # <class 'NoneType'>

nameC = bool(name)

print(nameC)  # False

返回值

使用关键字 return,得到函数返回值

python 复制代码
def add(n, m):
    return n+m

res = add(1,2)
print(res)

作用域

全局和局部

在局部作用域中可使用global声明变量是全局变量

ini 复制代码
n = 1

def add():
    global n
    n = 100
    m = n + 1
    print(m)

add()
add()
print(n)

十一、列表

数据容器:一种能存放多个数据的数据类型

定义列表

定义一个列表[元素1, 元素2, 元素3, 元素4...]

scss 复制代码
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() 将可迭代对象中的内容依次取出,追加至列表尾部
scss 复制代码
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 删除指定元素
scss 复制代码
# 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) 排序列表 无返回值
scss 复制代码
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> 返回元素总和
scss 复制代码
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)

循环遍历

  1. 通过 for item in list1: 获取每项元素item
  2. for index in range(len(list1)): 获取到元素下标index
  3. for index, item in enumerate(list1, start=5):获取到元素下标index和元素item,参数start可让计数从指定值开始

十二、元组

  • 元组是和列表类似的数据容器,区别是元组中的元素不可修改
  • 元组中存在可变类型(列表),那可变类型中的元素可修改

定义一个元组(元素1, 元素2, 元素3, 元素4...)

定义空元组

ini 复制代码
t1 = ()
t2 = tuple()

定义只有一个元素的元组:元素后须跟逗号

ini 复制代码
t1 = ('a',)
t2 = (1,)
ini 复制代码
# 定义元组
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() 返回元素出现的次数
scss 复制代码
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> 返回元素总和
python 复制代码
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

使用*对解包列表或元组

scss 复制代码
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() 从字符两端开始删除,直到遇到第一个不在字符串中的字符就停止
ini 复制代码
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

起始索引大于结束索引时,步长需为负数

ini 复制代码
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 同类型的才能相加

ini 复制代码
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必须为整数

go 复制代码
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...}

go 复制代码
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...})

go 复制代码
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接收的参数,可以是任意可迭代参数,但最终返回的一定是【不可变集合】

go 复制代码
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()

集合中不可嵌套【可变集合】,但可以嵌套【不可变集合】

ini 复制代码
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()

scss 复制代码
# 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()

scss 复制代码
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达到修改操作

csharp 复制代码
s1 = {1, 2, 3, 4, 5}
s1.remove(4)
s1.add(6)

查:

可通过【成员运算符】innot in去查看集合中是否有某个元素

ini 复制代码
s1 = {1, 2, 3, 4, 5}

res = 1 in s1
res2 = 1 not in s1
print(res, res2)

常用方法

difference()

css 复制代码
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()

css 复制代码
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()

ini 复制代码
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()

css 复制代码
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

ini 复制代码
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

shell 复制代码
# 交集:找出集合中共有的元素
# res = a & b # {4, 5, 6}

差集 集合a - 集合b

css 复制代码
# 差集 去除集合a中,集合b中也有的元素
# res = a - b # {1, 2, 3}

对称差集 集合a ^ 集合b

shell 复制代码
# 对称差集 在并集中去除掉交集
# res = a ^ b # {1, 2, 3, 7, 8, 9}

集合的循环遍历

集合没有下标,所以不能使用while,但可以使用for

shell 复制代码
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}

ini 复制代码
d1 = {'张三': 11, '李四': 2, '王五': 3, 'tom': 4}
print(d1, type(d1)) # {'张三': 11, '李四': 2, '王五': 3, 'tom': 4} <class 'dict'>

# 定义空字典
d2 = {}
d3 = dict()

字典key不能重复

ini 复制代码
# 字典的key不能重复,若出现重复,后者会覆盖前者
d1 = {'张三': 11, '李四': 2, '王五': 3, 'tom': 4, '张三': 22}
print(d1)

key必须是不可变类型,但value可为任意类型

ini 复制代码
# key必须是不可变类型,但value可为任意类型
d1 = {12: 12, '李四': 22}
d2 = {('你好', 'python'): 12, '李四': 22}
d3 = {['你好', 'python']: 23} # 报错

字典可以嵌套

css 复制代码
# 字典嵌套
d1 = {
    2001: {'张三': 11, '李四': 2, '王五': 3, 'tom': 4},
    2002: {'张三': 12, '李四': 22, '王五': 3, 'tom': 4},
    2003: {'张三': 13, '李四': 23, '王五': 3, 'tom': 4},
}

字典增删改查

bash 复制代码
</tbody>
操作 写法 说明 返回值
新增 字典[key] = 值 新增一组键值对(若键已存在则变为修改)
删除
删除 del 字典[key] 删除指定键对应的键值对(键不存在会报错)
删除 字典.pop(key, 默认值) 删除指定键对应的键值对 返回被删除键的值或默认值
删除 字典.clear() 删除所有键值对
修改
修改 字典[key] = 值 修改指定键对应的键值对(键不存在则为新增)
修改 字典.update(其他字典) 批量修改或合并多个键值对
查询
查询 字典[key] 根据键取值(键不存在会报错) 键对应的值
查询 字典.get(key, 默认值) 安全取值,键不存在则返回默认值,未设置默认值返回None 键对应的值或默认值

常用方法

方法 说明 返回值类型
字典.keys() 获取所有的键 'dict_keys'
字典.values() 获取所有的值 'dict_values'
字典.items() 获取所有的键值对 'dict_items'
arduino 复制代码
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__
ruby 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

# 创建实例对象
p1 = Person('张三', 19)

实例属性

  • 给实例添加属性(语法为:self.属性名 = 值 )
  • 通过实例.属性名 = 值 给实例添加的属性,就是实例属性
  • 实例属性只能通过实例访问,不能通过类访问,每个实例间的实例属性都是互不干扰的

通过 实例.dict 可以查看实例上的所有属性

shell 复制代码
# print(p1.__dict__) 
# {'name': '张三', 'age': 18, 'gender': 'male'}

类属性

  • 类属性可以通过类访问,也可以通过实例访问
  • 类属性通常用于保存 公共数据
scss 复制代码
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)

自定义方法

scss 复制代码
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()
# 你好~

实例方法

python 复制代码
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:就可访问类属性
  • 类方法通常用于实现与类相关的逻辑:操作类级别的信息,一些工厂函数
python 复制代码
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参数,所以其内部不会访问任何:类和实例相关的内容
  • 静态方法常用于定义:与类相关的工具方法
sql 复制代码
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):

python 复制代码
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的初始化

ruby 复制代码
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()

方法重写

当子类中定义一个与父类中相同的方法,那子类中的方法就会"重写"父类中的方法

python 复制代码
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('你好')

常用方法

  1. issubclass(Class, Class) 判断某个类是否为另一个类的子类
  2. isinstance(instance, Class) 判断某个对象是否为指定类或子类的实例
python 复制代码
...
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):

python 复制代码
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'>)

三种访问限制

  1. 共有属性 属性名 当前类、子类、类外部,都能访问
  2. 受保护的属性 _属性名 当前类、子类,都能访问
  3. 私有属性 __属性名 仅能在当前类中访问
python 复制代码
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方法

ruby 复制代码
@property
def age(self):
...

注册age属性的setter方法

ruby 复制代码
@age.setter
def age(self,value):
...
python 复制代码
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__ 当访问不存在属性时
python 复制代码
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类

css 复制代码
# 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)

多态

  • 多态:同一个方法,在不同的对象上调用时,能呈现出不同的行为
  • 多态又分 标准多态、鸭子多态

标准多态

标准多态的三个条件:继承关系、方法重写、类型限制

ruby 复制代码
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) # 不报错,但不推荐

鸭子多态

鸭子类型是一种编程风格,不检查对象的类型,只关注对象能否"做某件事"(是否有对应的方法)

ruby 复制代码
# 鸭子多态

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)

抽象类

抽象类 是一种不能直接实例化的类,它通常作为"规范",让子类去继承,并实现其中定义的的抽象方法

python 复制代码
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()
相关推荐
阿_旭2 小时前
基于YOLO26深度学习的铁轨部件缺陷检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】
人工智能·python·深度学习·铁轨部件缺陷检测
不只会拍照的程序猿2 小时前
《嵌入式AI筑基笔记02:Python数据类型02,从C的“硬核”到Python的“包容”》
开发语言·笔记·python
qq_416018722 小时前
用户认证与授权:使用JWT保护你的API
jvm·数据库·python
王夏奇2 小时前
笔记-关于python复习
python
AC赳赳老秦3 小时前
OpenClaw 全平台安装详解:Windows 10/11、macOS、Linux 零踩坑指南 (附一键脚本)
大数据·人工智能·python·django·去中心化·ai-native·openclaw
m0_743297423 小时前
实战:用Python分析某电商销售数据
jvm·数据库·python
databook3 小时前
从直觉到算法:贝叶斯思维的技术底层与工程实现
人工智能·python·机器学习
m0_716667073 小时前
使用PyQt5创建现代化的桌面应用程序
jvm·数据库·python
XW01059994 小时前
6-1输入列表,求列表元素和(eval输入应用)
python