1.基础知识
目录:
快捷键:
1.变量
2.标识符
3.常量
4.注释
5.编码
6.数据类型
7.字符串的4种定义方式
8.字符串格式化输出
9.转义字符
10.数据类型转换
11.数学运算符
12.赋值运算符
13.比较运算符
14.布尔类型
15.逻辑运算符
16.进制
17.输入 input()
python
# --------------------------------------
# 目录:
# 快捷键:
# 1.变量
# 2.标识符
# 3.常量
# 4.注释
# 5.编码
# 6.数据类型
# 7.字符串的4种定义方式
# 8.字符串格式化输出
# 9.转义字符
# 10.数据类型转换
# 11.数学运算符
# 12.赋值运算符
# 13.比较运算符
# 14.布尔类型
# 15.逻辑运算符
# 16.进制
# 17.输入 input()
# 快捷键:
# 1 Ctrl + S 全部保存
# 2 Ctrl + F 在本页面查询输入内容 ESC关闭
# 3 Ctrl + R 在本页面查询并替换内容 ESC关闭
# 4 Ctrl + G 跳转到指定行
# 5 Ctrl + / 注释本行,再次按,取消注释
# 6 Ctrl + y 删除本行
# 7 Alt + Ctrl + Enter 光标指向当前行的上一行(生成新的空行)
# 8 Shift + Enter 光标指向当前行的下一行(生成新的空行)
# 9 Ctrl + Alt + ↓ 快速复制当前行到下一行中
# 10 shift + Esc 快速关闭控制台 (光标要在控制台或输入区域中)
# 11 Alt + 1 收起或展开项目栏
# 12 Shift + F10 运行控制台中上一次的运行
# 13 Ctrl + Shift + F10 运行当前页面中的代码
# 13.1 Shift + F9 以DeBug模式运行当前页面中的代码
# 14 按住Ctrl + 函数名 快速跳转到函数体上
# 15 Alt + F1 + 1 (项目视图) 打开/定位到 当前文件-关联到的项目视图
# 15.1 Alt + F1 + 3 (文件结构) 打开/定位到 当前文件-关联到的文件结构
# 15.2 Alt + F1 + 8 (在资源管理器中显示) 打开/定位到 当前文件-关联到的文件所在磁盘的目录中
# 插件
# 1. Key Promoter X
# 2. CodeGlance
# 3. Rainbow Brackets
#coding=utf-8
#上面为文档编注释,Python3中可以不写。默认是utf-8
"""文档字符串 eq: 在该文件中,主要学习Python的基础语法"""
import sys
'张三'
18
print(25)
print('张三的体重是66kg')
print('张三的体重是',66)
# 1.变量
name = '张三'
age = 18
weight = 66
print(name,age,weight)
weight = 67
print(name,'的体重是',weight,'kg')
print('------------------1')
# 2.标识符
# 第一个字符必须以字母(a-z, A-Z)或下划线 _ 。
# 标识符的其他的部分由字母、数字和下划线组成。
# 标识符对大小写敏感,count 和 Count 是不同的标识符。
# 标识符对长度无硬性限制,但建议保持简洁(一般不超过 20 个字符)。
# 禁止使用保留关键字,如 if、for、class 等不能作为标识符。
name = '熊大'
Name = '熊二'
age_ = 18
_age_ =19
# 错 if = 10 标识符不要与内置函数同名
# ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif',
# 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or',
# 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
# 不报错,但不对 print = '熊三'
userName = '张三' # 小驼峰写法
UserName = '张三' # 大驼峰写法
user_name = '张三' # 蛇形写法 - Python推荐写法
print('------------------2')
# 3.常量 - 一旦被赋值,不希望被修改(区别于变量)
# Python一般约定使用全大写来表示常量,涉及多个单词时,用下划线做分割
# Python中没有强制的常量机制,Python的常量,本质还是变量,只不过我们约定好不去修改
AGE = 18
ADULT_AGE = 19
MAX_USERS = 1000
PASSING_SCORE = 60
MAX_USERS = 1100 # 常量可以被强制修改(不建议)
print(AGE, ADULT_AGE, MAX_USERS, PASSING_SCORE)
print('------------------3')
# 4.注释
# 单行注释:Python中单行注释以 # 开头
# 多行注释: 可以用多个 # 号,还有 ''' 和 """:
# 文件编码注释: 写在Python文件的开头,用于指定当前文件的字符编码。 #coding=utf-8
# 第一个单行注释
# 第二个注释
'''
第三多行注释
第四多行注释
'''
"""
第五多行注释
第六多行注释
"""
# 5.编码
# 默认情况下,Python3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串。
# 6.数据类型
# 可以使用 type() 返回数据类型
# String(字符串) str String
# Number(数字) int、float、bool、complex(复数)
# bool(布尔类型) True 或 False。
# List(列表)
# Tuple(元组)
# Set(集合)
# Dictionary(字典)
result = type('张三')
print(result) # <class 'str'>
print(type('18')) # <class 'str'>
print(type(18)) # <class 'int'>
print(type(18.2)) # <class 'float'>
print('------------------456')
# 整数(大整数分组)
# 整数,没有小数点的数字,可以是正数,负数,也可以是 0
age2 = 18
temp = -10
score = 0
# 当数很大时,我们可以使用下划线将数字进行分组,每3位一组,来让数字更易读
salary = 300_000
house_price = 3_200_000
graduates = 12_000_000
print(salary,house_price,graduates) # 300000 3200000 12000000
# Python中整数的上限值,取决于执行代码的计算机的内存和处理能力
a1 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999
print(a1)
a2 = 3 ** 2 # 3的2次方
print(a2) # 9
a3 = 9 ** 9999
# print(a3)
"""
Traceback (most recent call last):
File "D:\python\ws\file1\p1.py", line 103, in <module>
print(a3)
ValueError: Exceeds the limit (4300 digits) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit
"""
# b2 = a3 + 1
# print(b2)
sys.set_int_max_str_digits(4300)
print('------------------61')
# 浮点型: 带有小数点的数字
w = 65.2
bal = 1426.58
out_temp = -12.7
price = 120.0
print(w,bal,out_temp,price)
print(type(w),type(bal),type(out_temp),type(price))
print('------------------62')
# 浮点型的科学计数法表示
speed_of_sound = 3.4e+2 # 3.4乘以10的2次方
print(speed_of_sound,type(speed_of_sound)) # 340.0 <class 'float'>
world_population = 7.8e9 # 7.8乘以10的9次方
print(world_population,type(world_population)) # 7800000000.0 <class 'float'>
distance_sun_earth = 1.496E8 # 1.496乘以10的8次方
print(distance_sun_earth,type(distance_sun_earth)) # 149600000.0 <class 'float'>
speed_of_light = 2.998E+8 # 2.998乘以10的8次方
print(speed_of_light,type(speed_of_light)) # 299800000.0 <class 'float'>
one_ml = 1e-3 # 1乘以10的-3次方
print(one_ml,type(one_ml)) # 0.001 <class 'float'>
one_mg = 1E-3 # 1乘以10的-3次方
print(one_mg,type(one_mg)) # 0.001 <class 'float'>
print('------------------7')
# 7.字符串的4种定义方式
# 单引号和双引号的写法是等价的,二者都不能直接换行(要用圆括号才能换行),单引号用的多
msg1 = 'msg1'
msg11 = ('msg'
'11')
msg2 = "msg2"
# 三个双引号的写法,可以直接运行,并且可以作为多行注释使用。还可以作为文档字符串使用。
msg3 = """msg3"""
# 三个单引号的写法,可以直接运行,并且可以作为多行注释使用。
msg4 = '''msg4'''
print(msg1, msg11, msg2, msg3, msg4)
a4 = 233_000 + 6684
print(f'233_000 + 6684 = {a4}')
print('------------------71')
# 8.字符串格式化输出
name = '张三'
gender = '男'
weight = 66.6
age = 12
# 写法1:直接用 + 进行拼接。写起来麻烦,而且只能是字符串之间进行拼接。
print('我叫' + name + ',我是' + gender)
# 写法2:使用占位符 %s 字符串 %f 浮点数 %i 整数 %d 十进制整数 万能占位符 %s
print('我叫%s,我是%s, 我的体重是%f,年龄是%i, 年龄是%d' % (name, gender, weight, age, age))
print('我叫%s,我是%s, 我的体重是%s,年龄是%s' % (name, gender, weight, age))
# 写法3:使用f-string,是目前Python最推荐的一种方式。
print( f'我叫{name},我是{gender}生,我体重是{weight},年龄是{age}')
print('------------------81')
# 8.1 字符串占位符精度控制
# %m.ns
# m 控制整体宽度(整体宽度=整数宽度+小数点+小数宽度)。位数不够空格来补,位数小于整体宽度,则自动生效。整数是右对齐,负数是左对齐。
# n 精度控制,保留n位小数(n的默认值是6),不够0来补,截断时会四舍五入
weight1 = 65.55
print('我叫%-4.1s,我是%3.2s生, 我的体重是%-9.3f,年龄是%6.4d' % (name, gender, weight1, age))
print('------------------9')
# 9.转义字符
# 使用 \' 输出 '
print('Python中,可以使用单引号包裹一个字符串')
print("Python中,可以使用'包裹一个字符串")
print('Python中,可以使用\'包裹一个字符串')
# 使用 \" 输出 "
print('Python中,可以使用双引号包裹一个字符串')
print("Python中,可以使用\"包裹一个字符串")
# 使用 \n 进行换行
print('注册会员需要以下信息: \n姓名\n年龄\n手机号')
# 使用 \\ 输出 \
print('D:\\ndoc') # D:\ndoc
# 使用 \b 删除前一个字符
print('helloo\b') # hello
# 使用 \r 使光标回到本行开头,覆盖之前的输出
print('67%\r68%') # 68%
# 使用 \t 水平制表符(让光标跳到下一个制表位)
# 12341234
print('ab\tcd') # ab cd
print('abc\td') # abc d
print('abcde\tfg') # abcde fg
print('我\t是\t阜阳师范\t大学') # 我 是 阜阳师范 大学
print('------------------10')
# 10.数据类型转换
# 字符型、整型、浮点型
# 10.1 使用str将指定数据转换成字符串 str(...)
m1 = str(12)
m2 = str(12.1)
m3 = str(1.8e3)
m4 = str(12_0000)
print(m1, type(m1)) # 12 <class 'str'>
print(m2, type(m2)) # 12.1 <class 'str'>
print(m3, type(m3)) # 1800.0 <class 'str'>
print(m4, type(m4)) # 120000 <class 'str'>
# 10.2 把指定数据转换成整型 int(...)
n1 = int(15.6)
# n11 = int('15.6')
n2 = int('79')
n3 = int(' 79 ')
# n33 = int(' 7 9 ')
n4 = int(48)
print(n1, type(n1)) # 15 <class 'int'>
# print(n11, type(n11)) # 错误
print(n2, type(n2)) # 79 <class 'int'>
print(n3, type(n3)) # 79 <class 'int'>
# print(n33,type(n33)) # 错误
print(n4, type(n4)) # 48 <class 'int'>
# 10.3 将指定数据转为浮点数 float(...)
f1 = float(18)
f2 = float('15.6')
f3 = float(' 5.7 ')
f4 = float(14.8)
f5 = float('48')
print(f1, type(f1)) # 18.0 <class 'float'>
print(f2, type(f2)) # 15.6 <class 'float'>
print(f3, type(f3)) # 5.7 <class 'float'>
print(f4, type(f4)) # 14.8 <class 'float'>
print(f5, type(f5)) # 48.0 <class 'float'>
# 10.4 将指定内容转换为布尔类型 bool() ( 映射14.1 )
print(bool(0)) # False
print(bool(1)) # True
# Python中除了0以外的任何数,转为布尔值后都为True
print(bool(1)) # True
print(bool(0)) # False
print(bool(-1)) # True
# Python中除了空字符串以外的任何字符串,转为布尔值都是True
print(bool('a')) # True
print(bool('')) # False
print(bool('-9')) # True
print('------------------11')
# 11.数学运算符
# 假设变量 a=10,变量 b=21:
# + 加 - 两个对象相加 a + b 输出结果 31
# - 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -11
# * 乘 - 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 210
# / 除 - x 除以 y b / a 输出结果 2.1
# % 取模 - 返回除法的余数 b % a 输出结果 1
# ** 幂 - 返回x的y次幂 a**b 为10的21次方
# // 取整除 - 往小的方向取整数 9//2 = 4 -9//2 = -5
a = 21
b = 10
c = 0
c1 = a + b
print(c1) # 31
c2 = a - b
print(c2) # 11
c3 = a * b
print(c3) # 210
c4 = a / b
print(c4) # 2.1
c5 = a % b
print(c5) # 1
# 修改变量 a 、b 、c
a = 2
b = 3
c6 = a ** b
print(c6) # 8
a = 10.1
a1 = -10.1
b = 5
c6 = a // b
c7 = a1 // b
print(c6) # 2.0
print(c7) # -3.0
print('------------------12')
# 12.赋值运算符
# 假设变量a为10,变量b为20:
# = 简单的赋值运算符 c = a + b 将 a + b 的运算结果赋值为 c
# += 加法赋值运算符 c += a 等效于 c = c + a
# -= 减法赋值运算符 c -= a 等效于 c = c - a
# *= 乘法赋值运算符 c *= a 等效于 c = c * a
# /= 除法赋值运算符 c /= a 等效于 c = c / a
# %= 取模赋值运算符 c %= a 等效于 c = c % a
# **= 幂赋值运算符 c **= a 等效于 c = c ** a
# //= 取整除赋值运算符 c //= a 等效于 c = c // a
# := 海象运算符,这个运算符的主要目的是在表达式中同时进行赋值和返回赋值的值。Python3.8 版本新增运算符。
# 在这个示例中,赋值表达式可以避免调用 len() 两次:
# if (n := len(a)) > 10:
# print(f"List is too long ({n} elements, expected <= 10)")
a = 21
b = 10
c = 0
c = a + b
print(c) # 31
c += a
print(c) #52
c *= a
print(c) # 1092
c /= a
print(c) # 52.0
c21 = 2.1
a21 = 10
c21 %= a21
print(c21) # 2.1
c31 = 2
a31 = 3
c31 **= a31
print(c31) # 8
c41 = 20
a41 = 3
c41 //= a41
print(c41) # 6
print('------------------13')
# 13.比较运算符
# 假设变量 a 为 10,变量 b 为20:
# == 等于 - 比较对象是否相等 (a == b) 返回 False。
# != 不等于 - 比较两个对象是否不相等 (a != b) 返回 True。
# > 大于 - 返回x是否大于y (a > b) 返回 False。
# < 小于 - 返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。注意,这些变量名的大写。 (a < b) 返回 True。
# >= 大于等于 - 返回x是否大于等于y。 (a >= b) 返回 False。
# <= 小于等于 - 返回x是否小于等于y。 (a <= b) 返回 True。
a = 21
b = 10
c = 0
print(a == b) # False
print(a != b) # True
print(a < b) # False
print(a <= b) # False
print(a >= b) # True
print(a >= b) # True
# 以上这些运算符,也适用于 字符串 比较
# Python中字符串进行比较时,是依次比较每个字符的Unicode编码
# eq: a Unicode 97 我 Unicode 25105
# Python中可以使用如下方式进行字符与Unicode编码之间的转换。
# ① 使用ord()查看字符Unicode码
# ② 使用chr()将Unicode码转为字符
print(ord('a')) # 97
print(ord('我')) # 25105
print(chr(97)) # a
print(chr(25105)) # 我
print('------------------14')
# 14.布尔类型 boolean: True False
# 之前学的:
# ① 字符型:string 'a'
# ② 整型:int 108
# ③ 浮点型:float 14.5
# ④ 布尔类型 boolean: True False
d1 = True
d2 = False
print(d1, type(d1)) # True <class 'bool'>
print(d2, type(d2)) # False <class 'bool'>
d3 = 5 > 3
print(d3, type(d3)) # True <class 'bool'>
d4 = 7 < 2
print(d4, type(d4)) # False <class 'bool'>
# 布尔类型是int类型的子类型,底层的本质是用1表示True,用0表示False
print(int(True)) # 1
print(int(False)) # 0
print(4 + True) # 5
print(8 - True) # 7
print(True + True) # 2
print(True - True) # 0
print(False + False) # 0
print(True - False) # 1
print(7 > True) # True
print(False <= 0) # True
# 14.1 转换函数 -->跳转10.4
print('------------------15')
# 15.逻辑运算符
# 假设变量 a 为 10, b为 20:
# and x and y 布尔"与" -
# (如果两边都是True,则为True)
# (and 会先看左边,如果左边为 '假' 就直接返回左边,否则返回右边)如果 x 为 False,x and y 返回 x 的值,否则返回 y 的计算值。 (a and b) 返回 20。
# or x or y 布尔"或" -
# (如果两边至少1个为True,则为True)
# 如果 x 是 True,它返回 x 的值,否则它返回 y 的计算值。 (a or b) 返回 10。
# not not x 布尔"非" -
# (对一个字值反)
#(or 会先看左边,如果左边为 '真' 就直接返回左边,否则返回右边) 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 not(a and b) 返回 False
print(True and True) # True
print(True and False) # False
print(True or False) # True
print(not True) # False
print(8 > 7 and 10 < 2) # False
e1 = 10
e2 = 20
print(e1 and e2) # 20
print(2 - 2 and True) # 0
print('' and True) # ''
print(True and 8 / 2 ) # 4.0
print(3 + 3 and 3 * 4) # 12
print(e1 or e2) # 10
print(7 - 2 or False) # 5
print('你好' or '老陈') # '你好'
print(False or 8 / 2 ) # 4.0
print(2 - 2 or 3 * 4) # 12
print(not True) # False
print(not False) # True
print(not e1) # False
# and 具备 '逻辑短路' 的能力
print( False and 3 / 0) # False
# print( True and 3 / 0) # 报错
# or 同样具备 '逻辑短路' 的能力
print( True or 3 / 0) # True
# print( False or 3 / 0) # 报错
print('------------------16')
# 16.进制
# 十进制 (Decimal) 无前缀 基数:10 数字范围:0-9
# 9527 = 9 * 10**3 + 5 * 10**2 + 2 * 10**1 + 7 * 10**0
e1= 10
print(e1) # 10
# 二进制 (Binary) 前缀:0b 或 0B 基数:2 数字范围:0-1
# 1010 = 1 * 2**3 + 0 * 2**2 + 1 * 2**1 + 0 * 2**0 (十进制值为: 10)
e2 = 0b1010 # 十进制 10
print(e2) # 输出: 10
# 八进制 (Octal) 前缀:0o 或 0O 基数:8 数字范围:0-7
# 12 = 1 * 8**1 + 2* 8**0 等于 10(十进制)
e3 = 0o12
print(e3)
# 十六进制 (Hexadecimal) 前缀:0x 或 0X 基数:16 数字范围:0-9, A-F
# 0xA = 10 * 16**0 十进制 10
e4 = 0xA
print(e4) # 10
e5 = 0xA2
print(e5) # 162 = 10 * 16**1 + 2 * 16**0
# 十进制转其他进制的【字符串】
# 十进制转二进制 方法
# 25/2 = 12 1
# 12/2 = 6 0
# 6/2 = 3 0
# 3/2 = 1 1
# 1/2 = 0 1
# 从下到上 依次取出 25(10) = 11001(2)
print(bin(25)) # 0b11001
# 十进制转八进制
# 540/8 = 67 4
# 67/8 = 8 3
# 8/8 = 1 0
# 1/8 = 0 1
# 从下到上 依次取出 1034
print(oct(540)) # 0o1034
# 十进制转十六进制
# 463/16 = 28 15
# 28/16 = 1 12
# 1/16 = 0 1
# 从下到上 依次取出 1CF
print(hex(463)) # 0x1cf
# 去掉前缀
number = 42
print(bin(number)[2:]) # 输出: 101010
print(oct(number)[2:]) # 输出: 52
print(hex(number)[2:]) # 输出: 2a
# 其他进制转十进制 的【数字】 : 使用int()函数,指定原进制
print(int('101010', 2)) # 二进制转十进制: 42
print(int('52', 8)) # 八进制转十进制: 42
print(int('2a', 16)) # 十六进制转十进制: 42
print(int('2A', 16)) # 不区分大小写: 42
print('------------------17')
# 17.输入 input()
# 使用input()获取用户的输入
name = input('请输入你的姓名')
age = input('请输入你的年龄')
# input获取到的内容全部是字符串类型
print(type(name)) # <class 'str'>
print(type(age)) # <class 'str'>
# 将age转为整数
age = int(age)
# 打印信息
print(f'{name},你今年的年龄是{age},你明年的年龄是:{age+1}')
2.流程控制
目录:
1.分支
2.循环
- break 和 continue
python
# --------------------------------------
# 目录:
# 1.分支
# 2.循环
# 3. break 和 continue
# 流程控制语句:
# 顺序: 从上到下 (略)
# 分支: 单分支 双分支 多分支 嵌套分支
# 循环: while循环 for循环
# 1.分支
# 1.1 单分支: if
age = 19
# if True:
# if -1:
# if 0:
# if '':
# if '哈哈':
if age > 18:
print('成年')
print('成年的世界')
print('与if平级')
# 1.2 双分支:
# if
# else
age2 = 14
if age2 > 18:
print('成年')
print('成年的世界')
else:
print('未成年')
print('与if-else平级')
# 1.3 多分支
# if
# elif
# elif
# else
age3 = 19
if age3 <= 10:
print('条件1')
elif age3 <= 20:
print('条件2')
elif age3 <= 30:
print('条件3')
else:
print('条件4')
# 1.4 嵌套循环 在嵌套 if 语句中,可以把 if...elif...else 结构放在另外一个 if...elif...else 结构中。
# if 表达式1:
# 语句
# if 表达式2:
# 语句
# elif 表达式3:
# 语句
# else:
# 语句
# elif 表达式4:
# 语句
# else:
# 语句
# num = int(input("输入一个数字:"))
num = 12
if num % 2 == 0:
if num % 3 == 0:
print("你输入的数字可以整除 2 和 3")
else:
print("你输入的数字可以整除 2,但不能整除 3")
else:
if num % 3 == 0:
print("你输入的数字可以整除 3,但不能整除 2")
else:
print("你输入的数字不能整除 2 和 3")
print('------------------1')
# 2.循环
# 2.1 while循环
# while 判断条件(condition):
# 执行语句(statements)......
g1 = 1
while g1 <= 5: # 防止死循环 eq: while True
print('hello Python')
g1 += 1 # 防止死循环 eq: # g1 += 1
# 2.2 while 循环使用 else 语句
count = 7
while count < 5:
print(count, " 小于 5")
count = count + 1
else:
print(count, " 大于或等于 5")
# for循环
# for <variable> in <sequence>:
# <statements>
# else:
# <statements>
# 循环实例:
sites = ["Baidu", "Google", "Runoob", "Taobao"]
for site in sites:
print(site)
nums = [1,2,3]
for i in nums:
# nums.append(4) # nums中拼接4 [1,2,3,4]
print(i)
# 打印字符串中的每个字符
word = 'runoob'
for letter in word:
print(letter)
# 1 到 5 的所有数字: 整数范围值可以配合 range() 函数使用:
# range(..)函数:
# 值为: 左闭右开 range(1, 6) 包含1,不包含6 值为: 0 1 2 3 4 5
# range(6) = range(0, 6)
for number in range(1, 6):
print(number) # 1 2 3 4 5
print('--------')
# for...else
# for item in iterable:
# # 循环主体
# else:
# # 循环结束后执行的代码
# x = 0 Python中可以不用先定义
for x in range(6): # range(6) = range(0, 6)
print(x) # 0 1 2 3 4 5
else:
print("Finally finished!") # Finally finished!
sites = ["Baidu", "Google", "Runoob", "Taobao"]
for site in sites:
if site == "Runoob":
print("菜鸟教程!")
break
print("循环数据 " + site)
else:
print("没有循环数据!")
print("完成循环!")
# 循环数据 Baidu
# 循环数据 Google
# 菜鸟教程!
# 完成循环!
print('--------')
# print()介绍
# print()函数有一个end参数,默认值是\n(换行符):
print('a1')
print('a11', end= '\n')
print('a2', end='') # a2a3
print('a3', end=' ') # a2a3 a4
print('a4', end= '/') # a2a3 a4/a5
print('a5', end=',') # a2a3 a4/a5,a6
print('a6')
# 逗号分隔的多个值,默认用空格分隔
print('a', 'b', 'c') # a b c
# 使用sep参数修改分隔符
print("a", "b", "c", sep='-') # 输出:a-b-c
print("2024", "01", "15", sep='/') # 输出:2024/01/15
# 同时使用sep和end
print("a", "b", "c", sep='-', end='!!!\n') # 输出:a-b-c!!!
# 99乘法表
for i in range(1, 10):
for j in range(1, i+1):
print(f"{j}×{i}={i*j:2d}", end=" ")
print() # 换行
for i in range(1, 10):
for j in range(1, i+1):
print(f'{j}*{i}={i*j}', end='\t')
print() # 换行
print('------------------2')
# 3. break 和 continue
# break 立即终止循环,不再执行后续循环。语句可以跳出 for 和 while 的循环体。如果你从 for 或 while 循环中终止,任何对应的循环 else 块将不执行。
# continue 跳过当前循环块中的剩余语句,然后继续进行下一轮循环。
n = 5
while n > 0:
n -= 1
if n == 2:
break
print(n)
print('循环结束1。')
# 4
# 3
# 循环结束1。
n = 5
while n > 0:
n -= 1
if n == 2:
continue
print(n)
print('循环结束2。')
# 4
# 3
# 1
# 0
# 循环结束2。
for i in range(1, 6): # 1 2 3 4 5
if i == 2:
break
print(i)
print('循环结束3')
# 1
# 循环结束3
for i in range(1, 6): # 1 2 3 4 5
if i == 2:
continue
print(i)
print('循环结束4')
# 1
# 3
# 4
# 5
# 循环结束4
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, '等于', x, '*', n // x)
break
else:
# 循环中没有找到元素
print(n, ' 是质数')
# 2 是质数
# 3 是质数
# 4 等于 2 * 2
# 5 是质数
# 6 等于 2 * 3
# 7 是质数
# 8 等于 2 * 4
# 9 等于 3 * 3
3.函数
目录:
1.函数介绍:
2.函数的基本使用
3.函数中函数的使用
4.关键字参数
5.限制传参方式
6.参数的默认值
7.可变参数
8.特殊字面量 - None
9.函数的返回值
10.全局作用域vs局部作用域
11.函数的嵌套调用
12.递归调用
13.说明文档
python
# --------------------------------------
# 目录:
# 1.函数介绍:
# 2.函数的基本使用
# 3.函数中函数的使用
# 4.关键字参数
# 5.限制传参方式
# 6.参数的默认值
# 7.可变参数
# 8.特殊字面量 - None
# 9.函数的返回值
# 10.全局作用域vs局部作用域
# 11.函数的嵌套调用
# 12.递归调用
# 13.说明文档
# 1.函数介绍:
# 是组织好的,可重复使用的,用于执行特定代码的代码块。
# Python中的函数是一段有名字的代码块。我们提前编写好函数中要执行的代码。调用函数,函数中的代码就会执行。
# 函数的作用:
# ① 代码复用: 提高代码复用性,减少重复代码
# ② 结构清晰:让程序更易读,更易维护。
# ③ 模块化开发:把程序分成若干个小功能,便于团队合作。
# 函数的分类
# ① 内置函数:无需任何操作,直接使用。 eq: print() type() range()...
# ② 模块提供的函数:需要导入指定的模块后,才能使用。eq: math.sqrt() math.floor()...
# ③ 自定义函数:程序员自己定义的函数(先定义,再使用)
# 2.函数的基本使用
# 定义函数
# welcome() 报错 Python中的函数必要要先定义,再调用
def welcome():
print('welcome python')
# 调用函数
welcome()
welcome()
print('------------------2')
# 3.函数中函数的使用
# 函数的位置参数: 调用函数时,根据参数在函数定义中出现的顺序,把实参的值依次传递给对应的形参。
def order(num, dish): # 形参
print(f'你点的是:{num}份{dish}')
order(1,'辣子鸡') # 实参
order(2,'青椒炒肉') # 实参
# print(num) 报错:不能在函数外使用形参
# order(2) # 实参 参数个数不能多也不能少
print('------------------3')
# 4.关键字参数
# 调用函数时,通过 形参名 = 值 的形式传递实参。
def order1(num, dish, wel): # 形参
print(f'你点的是:{num}份{dish},{wel}')
order1(dish='面条', num=3, wel = '哈哈') # 可以不按照形参顺序传参。
order1(4, wel='呼呼', dish='青椒鱼') # 关键字和位置参数混用,使用关键字参数时,位置参数必须在关键字参数之前。
print('------------------4')
# 5.限制传参方式
# 具体规则: /前面只能用位置参数, * 后面只能用关键字参数
def greet1(name, / , gender, *, age, height): # name 必须用位置参数, age,height必须是关键字参数
print(f'我叫{name},性别{gender},年龄是{age},身高是{height}cm')
greet1('张三', '男', age= 18, height = 172) # 我叫张三,性别男,年龄是18,身高是172cm
greet1('张三', gender='男', age= 18, height = 172) # 我叫张三,性别男,年龄是18,身高是172cm
# def greet1(name, * , gender, /, age, height): //这种写法是错误的,/ 和 * 同时使用时,/ 必须在 * 的前面。
print('------------------5')
# 6.参数的默认值
# 定义函数时,通过 形参名=值 的形式,为参数制定一个默认值。
# 注意:默认参数必须要放在必选参数的后面,或者说: 某个形参,一旦设置了默认值,那它后面的所有形参,也必须要写默认值。
def order2(num=5 , dish ='炒粉'): # 形参
print(f'你点的是:{num}份{dish}')
order2()
order2(6)
order2(7, '剁椒鱼头')
order2(dish= '剁椒鱼头2', num= 8)
# def order2(num=5 , dish): # 报错
print('------------------6')
# 7.可变参数
# 7.1 可变位置参数
# 定义函数时,在形参名前面加 * , 可以接受任意数量的位置参数,并打包成一个元组。
def test1(*args):
print(args)
test1('张三', '男', 18, 172) # ('张三', '男', 18, 172)
# args是一个形参名,可以随意更改
# args中存放的是:函数调用时,所传入的所有位置实参
# args的数据类型是元组
# 7.2 可变关键字参数
# 定义函数时,在形参名前加 ** , 可以接受任意数量的关键字参数,并打包成一个字典。
def test2(**kwargs):
print(kwargs)
test2(name='张三', gender='男', age= 18, height = 172) # {'name': '张三', 'gender': '男', 'age': 18, 'height': 172}
# kwargs是一个形参名,可以随意更改
# kwargs中存放的是:函数调用时,所传入的所有关键字实参
# kwargs的数据类型是字典
# 可变位置参数,可变关键字参数,可以同时使用,但 必须先写可变位置参数
def test3(*args, **kwargs):
print(args) # ('张三', '男')
print(kwargs) # {'age': 18, 'height': 172}
test3('张三', '男', age= 18, height = 172)
# 可变位置参数,可变关键字参数,也能和 其他类型的参数一起使用
def test4(a, b, *args, c= '阜阳师范大学', **kwargs):
print(a) # 张三
print(b) # 男
print(args) # ('抽烟', '喝酒')
print(c) # fuyang
print(kwargs) # {'age': 18, 'height': 172}
test4('张三', '男', '抽烟', '喝酒', c = 'fuyang', age= 18, height = 172)
print('------------------7')
# 8.特殊字面量 - None
# ① 字符型:string 'a'
# ② 整型:int 108
# ③ 浮点型:float 14.5
# ④ 布尔类型 boolean: True False
# ⑤ NoneType类型:None
# ① None是一个特殊的字面量,它表示: 空值/无值/无意义
# msg = None
# 定义了msg的变量,但是目前还不知道它的具体类型。
# 不写None, 写 0 或 '' 或 False 可以吗? --- 最好别写
# None更中立,更开放,None是不暗示类型的。
# 如果确定msg以后是字符串类型,那就可以写 ''
# ② None的类型是 NoneType.
print(type(None)) # <class 'NoneType'>
# ③ None转为布尔值时,值是 False
msg1 = None
bool(msg1)
print(msg1) # None
msg1 = bool(msg1)
print(msg1) # False
# ④ None不能参与数学运算,也不能与字符串拼接
# msg2 = None
# result1 = msg2 +1 # 报错
# result2 = msg2 + '你好' # 报错
# ⑤ 如果我们不给函数设置返回值,函数会默认返回 None
print('------------------8')
# 9.函数的返回值
# 函数执行完毕后,会把执行结果交给调用者,这个执行结果就是 返回值。
# return 关键字; return会结束函数执行,并把return后面的值,作为函数的 返回值。
def add1(a, b):
# a + b # None
return a + b # 3
# print('a') # return 后面的代码不可执行
# return None
result6 = add1(1,2)
print(result6)
# 如果一个函数返回值为None,我们也经常说这个函数没有返回值。
result7 = print('hello Python')
print(result7) # None print函数是没有返回值的
print('------------------9')
# 10.全局作用域vs局部作用域
# 变量能起作用的范围(变量在哪里能用,在哪里不能用)
# 全局作用域:整个.py文件最外层的范围,就是全局作用域。
# 局部作用域:函数的内部范围,就是局部作用域。
r1 = 100 # 全局作用域:在当前文件的任意位置都能使用
r2 = 'hello'
def def0():
r3 = 10000 # 局部作用域:只能在当前函数中内部使用。
r4 = 'hello Python'
r1 = 1000
print(r1) # 1000 就近取值原则
print(r2) # hello
print(r3) # 10000
def0()
# print(r3) # 报错
print(r1) # 100
# global用法:
r5 = 1
def def1():
global r5 # r5开启全局变量。此时下面的 r5 = 2 就是在修改 r5 = 1 的值,后续(全局+局部)都得到修改后的值
r5 = 2
print(r5) # 2
def1()
print(r5) # 2
# 10.1 局部作用域 和 局部变量,会在函数调用时创建,在函数 执行结束后 销毁。即:多次调用函数,执行结果是一样的。
def def2():
r6 = 10
r6 += 1
print(r6)
def2() # 11
def2() # 11
# 10.2 全局作用域 和 全局变量, 会在程序开始时创建,在程序结束后销毁
r6 = 20
def def3():
global r6
r6 += 1
print(r6)
def3()
print(r6) # 21 21
def3()
print(r6) # 22 22
print('------------------10')
# 11.函数的嵌套调用
# 在一个函数的执行过程中,去调用了另外一个函数
def def4():
print('def4')
def def5():
def4()
print('def5')
def def6():
def5()
print('def6')
def6()
# def4
# def5
# def6
print('------------------11')
# 12.递归调用
# 指函数自己调用自己的一种操作
# 把一个很大的事,拆解为无数个套路一样的小事。
def def7(n):
if n < 8:
print(f'hello dog-{n}')
n += 1
def7(n)
else:
print('end')
def7(5)
def def8(n):
if n > 1:
def8(n -1)
print(f'hello, {n}') # 5 4 3 2 1 栈 底--> 顶
def8(5)
# hello, 1
# hello, 2
# hello, 3
# hello, 4
# hello, 5
def def9(n):
if n > 1:
def9(n -1)
print(f'hello, {n}') # 5 4 3 2 栈 底--> 顶
def9(5)
# hello, 2
# hello, 3
# hello, 4
# hello, 5
# 使用递归求一个数的阶乘
def fac(num):
if num == 0:
return 1
return num * fac(num-1)
result10 = fac(5)
print(result10) # 120
print('------------------12')
# 13.说明文档
# 说明文档:写在函数里的文字说明,用来描述:函数的功能,需要哪些参数,返回什么结果。
def def10(n1, n2):
"""
计算2个数相加的结果
:param n1: 第一个数
:param n2: 第二个数
:return: 二者相加的结果
"""
return n1 + n2
def10(1, 2)
# 案例; 计算1个人7天的总运动量,平均值,是否达到目标
def calc_total(*nums):
return sum(nums)
def calc_avg(total, days=7):
return total / days
def check_success(total, goal =120):
if total > goal:
return 'SUCCESS'
else:
return 'FAIL'
def main(title, duration):
"""
主函数
:param title: 比赛名
:param duration: 持续时间
:return: 返回结果
"""
print(f'【{title}】【{duration}】挑战赛(请输入每天的运动量)')
num1 = int(input('第1天:'))
num2 = int(input('第2天:'))
num3 = int(input('第3天:'))
num4 = int(input('第4天:'))
num5 = int(input('第5天:'))
num6 = int(input('第6天:'))
num7 = int(input('第7天:'))
# 计算运动总量
total = calc_total(num1, num2, num3, num4, num5, num6, num7)
# 计算平均值
avg = calc_avg(total)
# 判断是否挑战成功
result11 = check_success(total)
print(f'{total}, {avg:.1f}, {result11}') # :1f 保留1位小数
main('仰卧起坐', 7)
4.1 数据容器1
目录:
数据容器
1.数据容器-列表(list)
1.1 列表中下标(索引值)
1.2 新增(Create)操作
1.3 删除(Delete)操作
1.4 修改(Update)操作
1.5 查询(Read)操作
1.6 列表的常用方法
1.7 常用内置函数
1.8 列表-循环遍历
1.9 列表-案例练习
1.10 列表-特点总结
2.数据容器-元组(tuple)
2.1 介绍
2.2 定义元组:
2.3 注意事项
2.4 定义空元组
2.5 定义只有一个元素的元组
2.6 元组中的常用方法:
2.7 元组中常用的内置函数
2.8 元组的循环遍历
2.9 元组总结
3.函数-解包列表或元组传参
4.数据容器-字符串(str)
4.1 介绍
4.2 常用方法
4.3 常用内置函数
4.4 字符串的循环遍历
5.序列
5.1 序列的切片操作
5.2 序列的其他操作-相加
5.3 序列的其他操作-相乘
python
# --------------------------------------
# 目录:
# 数据容器
# 1.数据容器-列表(list)
# 1.1 列表中下标(索引值)
# 1.2 新增(Create)操作
# 1.3 删除(Delete)操作
# 1.4 修改(Update)操作
# 1.5 查询(Read)操作
# 1.6 列表的常用方法
# 1.7 常用内置函数
# 1.8 列表-循环遍历
# 1.9 列表-案例练习
# 1.10 列表-特点总结
# 2.数据容器-元组(tuple)
# 2.1 介绍
# 2.2 定义元组:
# 2.3 注意事项
# 2.4 定义空元组
# 2.5 定义只有一个元素的元组
# 2.6 元组中的常用方法:
# 2.7 元组中常用的内置函数
# 2.8 元组的循环遍历
# 2.9 元组总结
# 3.函数-解包列表或元组传参
# 4.数据容器-字符串(str)
# 4.1 介绍
# 4.2 常用方法
# 4.3 常用内置函数
# 4.4 字符串的循环遍历
# 5.序列
# 5.1 序列的切片操作
# 5.2 序列的其他操作-相加
# 5.3 序列的其他操作-相乘
# 数据容器
# 一种存放多个数据的数据类型。
# 好处:可以更高效的管理成批的数据,且便于存储,访问。
# ① 容器中的每一个数据,又称为: 每一个元素
# ② Python中有很多种数据容器
# 包含: 列表(list) 元组(tuple) 字符串(str) 集合(set) 字典(dict)
print('------------------列表')
# 1.数据容器-列表(list)
# 定义列表: list1 = [元素0, 元素1, 元素2, ...]
# 序列中的每个值都有对应的位置值,称之为索引,第一个索引是 0,第二个索引是 1,依此类推。
# 列表的数据项不需要具有相同的类型
list1 = [] # 定义空列表:列表中的数据,后期会通过特定写法填充。
list2 = [34, 35, 36, 37]
list3 = ['北京', True, 36, 37]
list4 = [12, '北京', False, None, 12.13, [1, 3]] # 嵌套列表 [1, 3]
print(f'{list1}\n{list2}\n{list3}\n{list4}')
# []
# [34, 35, 36, 37]
# ['北京', True, 36, 37]
# [12, '北京', False, None, 12.13, [1, 3]]
# 1.1 列表中下标(索引值)
# 下标(索引值):列表中的元素的位置编号。
# 正索引:从左往右数, 其实元素是 0 随后是1,2,3,4...
nums1 = [1,2,3,4] # 正索引依次为:0,1,2,3
# 负索引:从右往左数,其实元素是 -1, 随后-2,-3,-4...
nums2 = [1,2,3,4] # 负索引依次为:-1,-2,-3,-4...
# 作用:通过 [下标] 的形式,去除对应元素。
print(nums1[0]) # 1
print(nums1[-4]) # 1
# print(nums1[4]) # 报错:IndexError: list index out of range
print(list4[-1][1]) # 3
print('------------------1.1')
# 列表中操作: 新增(Create),查询(Read),删除(Delete),修改(Update)
# 1.2 新增(Create)操作
# 方式1:
# 语法:列表.append(元素) 解释:在列表尾部追加一个元素。
# append() 方法
# 方法 vs 函数 : 当一个函数隶属于某个对象时,那该函数就是该对象的一个方法。
# b() 调用b函数 a.b() 调用a的b方法
nums3 = [1, 2, 3, 4]
nums3.append(5)
print(nums3) # [1, 2, 3, 4, 5]
# 方式2:
# 语法: 列表.insert(下标, 元素) 解释:在列表指定下标处添加一个元素。 原元素向后移动1位
nums4 = [1, 2, 3, 4]
nums4.insert(2,666)
print(nums4) # [1, 2, 666, 3, 4]
# 方式3:
# 语法:列表.extend(可迭代对象) 解释:将 可迭代对象 中的内容依次取出,追加到列表尾部。
# 可迭代对象:字符串 '陈振' / range(1, 4) / [1,2,3,4]
nums5 = [1, 2, 3, 4]
nums5.extend('阜师院') # 依次取出: 阜 师 院
nums5.extend([5, 6, 7, '陈陈']) # 无返回值
print(nums5) # [1, 2, 3, 4, '阜', '师', '院', 5, 6, 7, '陈陈']
print('------------------1.2')
# 1.3 删除(Delete)操作
# 方式1:
# 语法: 列表.pop(下标) 解释:删除指定位置的元素,并将删除的元素返回。
nums6 = [10, 20, 30, 40]
n6 = nums6.pop(2)
print(nums6) # [10, 20, 40]
print(n6) # 30
# 方式2:
# 语法: 列表.remove(值) 解释:删除列表中第一次出现的指定值
nums7 = [10, 20, 30, 40, 10]
n7 = nums7.remove(10) # 无返回值 None
print(nums7) # [20, 30, 40, 10]
print(n7) # None
# 方式3:
# 语法: 列表.clear() 解释:删除列表中的所有元素(变成一个空列表)
nums8 = [10, 20, 30, 40, 10]
n8 = nums8.clear() # 无返回值 None
print(nums8) # []
print(n8) # None!
# 方式4:
# 语法: del 列表[下标] 解释:删除指定位置的元素。
nums9 = [10, 20, 30, 40]
del nums9[2] # 无返回值
print(nums9) # [10, 20, 40]
print('------------------1.3')
# 1.4 修改(Update)操作
# 语法: 列表[下标] = 值 解释:通过下标修改指定位置的元素。
nums10 = [10, 20, 30, 40, 10, 60]
nums10[2] = 300
print(nums10) # [10, 20, 300, 40, 10, 60]
print('------------------1.4')
# 1.5 查询(Read)操作
# 语法:列表[下标] 解释:通过下标获取制定位置的元素。
nums11 = [10, 20, 30, 40, 10, 60]
n11 = nums11[2]
print(n11) # 30
print('------------------1.5')
# 1.6 列表的常用方法
# 方法1: 元素下标 = 列表.index(值)
# 解释:查找指定元素在列表中第一次出现的下标
# 返回值: 元素下标
nums12 = [10, 20, 30, 40, 10, 20, 60, [100, 70]]
n12 = nums12.index(20)
print(n12) # 1
# index 不会深入到嵌套列表中查询。
# nums12.index(100) # 报错:ValueError: 100 is not in list
# 方法2:元素出现的次数 = 列表.count(值)
# 解释:统计某个元素在列表中出现的次数。
# 返回值: 元素出现的次数
nums13 = [10, 20, 30, 40, 10, 20, 60, [100, 70]]
n13 = nums13.count(20)
print(n13) # 2
n100 = nums13.count(100)
# count统计列表中不存在的元素时,不会报错,会返回 0
# count 不会深入到嵌套列表中查询。
print(n100) # 0
# 方法3:列表.reverse()
# 解释: 反转列表(会该表原列表本身),无需参数
# 返回值: 无
nums14 = [10, 20, 30, 40, 10, 20, 60, [100, 70]]
nums14.reverse()
# reverse 不会深入到嵌套列表中查询。
print(nums14) # [[100, 70], 60, 20, 10, 40, 30, 20, 10]
# 方法4:列表.sort(reverse=布尔值)
# 解释:对列表排序(默认: 从小到大,会改变原列表本身)
# reverse 用于控制排序方式。 reverse = True 从大到小
# 返回值: 无
# 场景1:若列表中的元素: 都是数字,则按照数字的大小顺序进行排序。
nums15 = [10, 20, 30, 40, 10, 20, 60]
nums15.sort()
print(nums15) # [10, 10, 20, 20, 30, 40, 60]
nums15.sort(reverse=True)
print(nums15) # [60, 40, 30, 20, 20, 10, 10]
# 场景2:若列表中的元素: 既是数字,又有字符串,那就会报错。
nums15 = [10, 20, 30, 40, 10, 20, 60, '老陈']
# nums15.sort()
# print(nums15) # 报错 TypeError: '<' not supported between instances of 'str' and 'int'
# 场景3:若列表中元素: 都是字符串,则按照字符串的 Unicode编码 大小进行排序。(默认: 从小到大)
str1 = ['李传涛','陈振','李赛赛','王伟健','张俊彦','张雪峰']
# sort()方法不会深入到嵌套循环内部
str1.sort()
print(ord('张'), ord('李'), ord('王'), ord('陈'))
print(str1) # ['张俊彦', '张雪峰', '李传涛', '李赛赛', '王伟健', '陈振']
# 注意: 所有的列表方法,都只作用于'当前层'的元素(浅层操作)。不会自动进入'嵌套的' '里层'结构中!!!
print('------------------1.6')
# 1.7 常用内置函数 (适用于所有 数据容器)
# 方法1: sorted(数据容器, reverse= 布尔值)
# 解释:对容器排序(从小到大,不会改变原容器)
# reverse用于控制排序方式
# 返回值:经过排序后的新容器
# 场景1:若列表中的元素: 都是数字,则按照数字的大小顺序进行排序。
# 场景2:若列表中的元素: 既是数字,又有字符串,那就会报错。
# 场景3:若列表中元素: 都是字符串,则按照字符串的 Unicode编码 大小进行排序。(默认: 从小到大)
nums16 = [10, 20, 30, 40, 10, 20, 60]
nums166 = sorted(nums16)
print(nums16) # [10, 20, 30, 40, 10, 20, 60]
print(nums166) # [10, 10, 20, 20, 30, 40, 60]
num1666 = sorted(nums16, reverse=True)
print(num1666) # [60, 40, 30, 20, 20, 10, 10]
# 方法2:len(数据容器)
# 解释:获取容器中元素的个数
# 返回值: 元素个数
nums17 = [10, 20, 30, 40, 10, 20, 60, [80,90]]
count177 = len(nums17)
print(count177) # 8
# 方法3: max(数据容器)
# 解释: 返回容器中 或 多个值中的最大值。
# 返回值: 最大值
nums18 = [10, 20, 30, 40, 10, 20, 60]
max188 = max(nums18)
print(max188) # 60
# 如果容器中的元素:都是字符串,那max(也适用于min)会返回:Unicode编码最大的字符。
nums1888 = ['张','李','王','陈']
max18888 = max(nums1888)
print(ord('张'), ord('李'), ord('王'), ord('陈')) # 24352 26446 29579 38472
print(max18888) # 陈
# 方法4: min(数据容器)
# 解释: 返回容器中 或 多个值中的最小值。
# 返回值: 最小值
nums19 = [10, 20, 30, 40, 10, 20, 60]
min199 = min(nums19)
print(min199) # 10
# 方法5: sum(数据容器)
# 解释: 对容器中所有的元素求和(只能是数值类型,字符串不能使用sum)!
# 返回值:所有元素之和
nums20 = [10, 20, 30, 40, 10, 20, 60]
# nums20 = [10, 20, 30, 40, 10, 20, 60, '陈'] # 报错
# nums20 = [10, 20, 30, 40, 10, 20, 60,[70, 40]] # 报错
sum200 = sum(nums20)
print(sum200) # 190
print('------------------1.7')
# 1.8 列表-循环遍历
# 遍历: 把容器中的元素依次取出,并对它们进行处理的过程.
# 分为2种: while循环 / for循环
# 1.81 while循环遍历
nums21 = [10, 20, 30, 20, 60]
index = 0 # 这里index不能写 = 1, 不能nums21[0]数据就丢失了
while index < len(nums21):
print(nums21[index], end=' ') # 10 20 30 20 60
index += 1
print()
# 1.82 for循环遍历
# 方式1:
nums22 = [10, 20, 30, 20, 60]
for item in nums22:
print(item, end=' ') # 10 20 30 20 60
print()
# 方式2:
for index in range(len(nums22)):
print(nums22[index], end=' ') # 10 20 30 20 60
print()
# 方式3: 同时打印下标和数据元素
for index, item in enumerate(nums22, start= 10): # start 只是修改用于展示 '编号' index,而不是列表中真实的索引。
print(index, item, nums22[1], end=' ')
print()
# 10 10 20
# 11 20 20
# 12 30 20
# 13 20 20
# 14 60 20
print('------------------1.8')
# 1.9 列表-案例练习
print('请输入学生成绩,输入"结束"停止可录入')
score_list= []
# 持续循环,让用户输入学生成绩
while True:
# data = input('请输入成绩:') # 测试时,请放开此行,注释掉下面一行。
data = '结束'
if data == '结束':
break
else:
score_list.append(int(data))
# 如果score_list中有数据,则开始统计
if score_list:
# 统计平均分
avg = sum(score_list)/len(score_list)
# 合格人数
pass_count = 0
# 优秀人数
excellent_count = 0
# 遍历列表,开始统计
for item in score_list:
if item > 60:
pass_count += 1
if item > 90:
excellent_count += 1
# 合格率
pass_rate = pass_count / len(score_list) * 100
# 优秀率
excellent_rate = excellent_count / len(score_list) * 100
# 打印信息
print('************统计信息如下:***************')
print(f'总人数为:{len(score_list)}')
print(f'最高分为:{max(score_list)}')
print(f'最低分为:{min(score_list)}')
print(f'合格人数为:{pass_count}人')
print(f'合格率为:{pass_rate:.1f}%')
print(f'优秀人数为:{excellent_count}')
print(f'优秀率为:{excellent_rate:.1f}')
print(f'平均分数为:{avg:.1f}')
else:
print('你没有输入任何成绩!')
print('------------------1.9')
# 1.10 列表-特点总结
# 1. 可存放不同类型的元素。
# 2. 元素是有序存储的(正索引,负索引)。
# 3. 列表中的元素允许重复。
# 4. 元素是运行修改的(增、删、改、查、其他操作)
# 5. 长度不固定,可以随着操作自动调整大小。
# 列表是最常用的数据容器,当遇到要 '存储一批数据' 的场景时,首选列表。
print('------------------元组')
# 2.数据容器-元组(tuple)
# 2.1 介绍
# 定义: 元组是一种和列表类似的数据容器,它和列表的区别是:元组中的元素 不可修改。
# 列表: 增删改查 元组:查
# t = (元素1, 元素2, 元素3, ...)
# 2.2 定义元组:
t1 = (1, 2, 3, 5, 67, 243)
t2 = ('陈','李','王','张')
t3 = (100, True, '陈', None)
t4 = (100, True, '陈', None, (12, 22, '陈2'))
# 通过下标取值:
print(t1[2]) # 3
print(t2[-1]) # 张 访问下标为 -1 的元素
# 2.3 注意事项
# 注意1:元组中的元素不可修改。
# t1[1] = 100 # 报错:TypeError: 'tuple' object does not support item assignment
# 注意2:元组中如果存放了可变类型(列表),那可变类型中的内容任可修改。
t5 = (1, 2, 3, 67, 243, ['陈', 10, (10, 20)])
# t5[1] = 20 # 报错
# t5[5] = 30 # 报错
t5[5][1] = 100
print(t5) # 可以修改,输出: (1, 2, 3, 67, 243, ['陈', 100, (10, 20)])
# t5[5][2][0] = 100 # 报错
print('------------------2.3')
# 2.4 定义空元组
t6 = ()
t7 = tuple()
print(type(t6)) # <class 'tuple'>
print(type(t7)) # <class 'tuple'>
print('------------------2.4')
# 2.5 定义只有一个元素的元组
# 需要加 逗号 因为Python会认为是一个字符串,而不是元组
t8 = ('你好',)
t9 = (18,)
print('------------------2.5')
# 2.6 元组中的常用方法:
# 方法1: index()方法: 获取指定元素在元组中第一次出现的下标。
t10 = (1, 2, 3, 5, 67, 243)
t100 = t10.index(67)
print(t100) # 4
# 方法2: count()方法:统计指定元素在元组中出现的次数。
t11 = (1, 2, 3, 243, 3, 243, 5, 67, 243)
t111 = t11.count(243)
print(t111) # 3
print('------------------2.6')
# 2.7 元组中常用的内置函数
# 方法1: max函数,返回元组中的最大值
t12 = (10, 20, 30, 40, 10, 20, 60)
t122 = max(t12)
print(t122) # 60
# 如果容器中的元素:都是字符串,那max(也适用于min)会返回:Unicode编码最大的字符。
t13 = ('张','李','王','陈')
t133 = max(t13)
print(ord('张'), ord('李'), ord('王'), ord('陈')) # 24352 26446 29579 38472
print(t133) # 陈
# 方法2:min函数,返回元组中的最小值
t13 = (10, 20, 30, 40, 10, 20, 60)
t133 = min(t13)
print(t133) # 10
# 方法3:len函数,返回元组中元素的个数(元组长度)
t14 = (10, 20, 30, 40, 10, 20, 60)
t144 = len(t14)
print(t144) # 7
# 方法4:sorted函数,对元组进行排序(不修改原元组,返回一个 新的列表)
t15 = (10, 20, 30, 40, 10, 20, 60)
t155 = sorted(t15) # 返回的是 列表
print(t155) # [10, 10, 20, 20, 30, 40, 60]
t1555 = tuple(t155) # 列表 转成 元组
print(t1555) # (10, 10, 20, 20, 30, 40, 60)
# 方法5: sum函数,统计元组中所有元素的和(元素必须是数字)
t16 = (10, 20, 30, 40, 10, 20, 60)
t166 = sum(t16)
print(t166) # 190
# 实际开发中的元组,不一定是我们自己定义的,eq: 函数的可变参数 *args 就是一个元组
def demo(*args):
print(type(args)) # <class 'tuple'>
return sum(args)
result = demo(1,2,3,4,5,6,7,8,9,10)
print(result) # 55
# 2.8 元组的循环遍历
t17 = (10, 20, 30, 40, 10, 20, 60)
index = 0
while index < len(t17):
print(t17[index], end=' ') # 10 20 30 40 10 20 60
index += 1
print()
for item in t17:
print(item, end=' ') # 10 20 30 40 10 20 60
print()
print('------------------2.8')
# 2.9 元组总结
# 1. 可存放不同类型的元素。
# 2. 元素是有序存储的(正索引,负索引)。
# 3. 元组中的元素允许重复。
# 4. 元素不允许修改(不能:增删改 只能:查)
# 5. 长度固定(一旦创建,元素个数不能增减)。
# 元组是一种 '只读' 的数据容器,想保持一批 '不会改变的数据' 时,首选元组。
print('------------------2.9')
# 3.函数-解包列表或元组传参
# 定义函数时,使用 *args(变量不一定非要用args,比如写 *data也可以),将收到的多个参数,打包成一个元组
def test(*args):
print(f'我是test函数,我收到的参数是: {args},参数类型是:{type(args)}')
list1 = [100, 200, 300, 400]
tuple1 = ('陈', '张', '李')
# 函数调用时,正向传递: 列表或元组
# test(list1) # 我是test函数,我收到的参数是: ([100, 200, 300, 400],),参数类型是:<class 'tuple'>
# test(tuple1) # 我是test函数,我收到的参数是: (('陈', '张', '李'),),参数类型是:<class 'tuple'>
# 函数调用时,使用 * 对: 列表 或 元组 进行解包后,再传递参数。
test(*list1) # 我是test函数,我收到的参数是: (100, 200, 300, 400),参数类型是:<class 'tuple'>
# test(*tuple1) # 我是test函数,我收到的参数是: ('陈', '张', '李'),参数类型是:<class 'tuple'>
print('------------------3')
# 4.数据容器-字符串(str)
# 4.1 介绍
# 数据容器的角度:字符串就是存放多个字符的容器。
# 字符串支持下标(索引值)
# 0123456
msg = 'welcome'
print(msg[3]) # c
print(msg[-1]) # e
# 字符串中的字符不可修改
msg1 = 'welcome'
# msg[0] = 'a' # 报错
# 字符串不能嵌套(字符串中的每一个元素都是单个字符).以下都不是字符串嵌套
# msg2 = 'h'ell'0' # 报错
msg3 = 'h"ell"o'
msg4 = 'h\'ell\'o'
print(msg3, msg4, end= ' ')
print('------------------4.1')
# 4.2 常用方法
# 方法: index 方法: 获取指定字符在字符串中第一次出现的下标。
msg5 = 'welcome to shanghai'
msg55 = msg5.index('o')
print(msg55) # 4
# 方法2:split 方法:将字符串按照指定字符进行分割,并返回一个列表。
# 如果按照一个不存在的字符分割,返回 原元素列表
# 按照空格分割也可以。
msg6 = 'welcome@to@shanghai'
msg66 = msg6.split('@')
print(msg66) # ['welcome', 'to', 'shanghai']
msg666 = msg6.split('d')
print(msg666) # ['welcome@to@shanghai']
# 方法3: replace 方法:将字符串中的某个 字符串片段, 替换成 目标字符串。
msg7 = 'welcome to shanghai'
msg77 = msg7.replace('o', 'O')
print(msg77) # welcOme tO shanghai
msg77 = msg7.replace('shanghai', 'hefei')
print(msg77) # welcome to hefei
# 方法4: count方法: 统计指定字符在字符串中出现的次数。
msg8 = 'welcome to shanghai'
msg88 = msg8.count('o')
print(msg88) # 2
# 方法5: 统计指定字符在字符串中出现的次数。
msg9 = 'welcome to shanghai'
msg99 = msg9.count('o')
print(msg99) # 2
# 方法6:strip方法:从某个字符串中删除指定字符串中的任意字符。
# 规则:从字符串的两端开始删除,直到遇到第一个不在指定字符串中的字符就停下。
# strip方法是不改变原字符串的,会返回一个新的字符串。
msg10 = '666welcome to shanghai666'
msg1010 = msg10.strip('6')
print(msg10) # 666welcome to shanghai666
print(msg1010) # welcome to shanghai
msg11 = '1234welcome to shanghai4321'
msg1111 = msg11.strip('1324')
print(msg1111) # welcome to shanghai
msg12 = '34215welcome12 to34 shanghai4132'
msg1212 = msg12.strip('5432')
print(msg1212) # 15welcome12 to34 shanghai41
# 常用方法:去除字符串两边空格。
msg13 = ' 上海 '
msg1313 = msg13.strip()
print(msg13) # 上海
print(msg1313) # 上海
print('------------------4.2')
# 4.3 常用内置函数
# 方法1; len函数:统计字符串中,字符的个数。(字符串长度) 包含空格。
msg14 = 'welcome to shanghai'
msg1414 = len(msg14)
print(msg1414) # 19
# 不常用的函数
# max函数:返回字符串中Unicode编码值最大的那个字符(不是下标)
# min函数:返回字符串中Unicode编码值最小的那个字符(不是下标)
# sorted函数:将字符串中Unicode编码值排序,返回新列表(不改变原字符串)
print('------------------4.3')
# 4.4 字符串的循环遍历
msg15 = 'welcome to shanghai'
# while循环遍历
index = 0
while index < len(msg15):
print(msg15[index], end=' ') # w e l c o m e t o s h a n g h a i
index += 1
print()
# for循环遍历
for item in msg15:
print(item, end=' ') # w e l c o m e t o s h a n g h a i
print()
print('------------------4')
# 5.序列
# 序列:能连续存放元素的数据容器,元素有先后循序,且可以通过下标访问。
# 列表,元组,字符串 都是序列。
# 5.1 序列的切片操作
# 切片:从序列中按照指定范围,取出一部分元素,形成一个新的序列的操作。
list1 = [100, 200, 300, 400, 500, 600, 700]
list2 = [300, 400, 500, 600]
# 语法: 序列[起始索引:结束索引:步长]
# 步长:步长为n : 每次隔 n-1位取出
# 比如: 步长为 1 从起始索引 到 结束索引(不包括结束索引)跳过0位(依次)取出数据组成新的序列。
# 比如: 步长为 2 从起始索引 到 结束索引(不包括结束索引)跳过1位取出数据组成新的序列。
# 5.11 对列表进行切片
list3 = [10, 20, 30, 40, 50, 60, 70]
list4 = list3[0:5:1]
# 索引: 0 1 2 3 4 5 6
print(list3) # [10, 20, 30, 40, 50, 60, 70]
print(list4) # [10, 20, 30, 40, 50]
list5 = list3[0:5:2]
print(list5) # [10, 30, 50]
print('----------1')
list55 = list3[::]
print(list55) # [10, 20, 30, 40, 50, 60, 70]
list555 = list3[:999:]
print(list555) # [10, 20, 30, 40, 50, 60, 70]
list5555 = list3[2::]
print(list5555) # [30, 40, 50, 60, 70]
list55555 = list3[::2]
print(list55555) # [10, 30, 50, 70]
print('----------2')
# 注意: 当起始索引 大于 结束索引时,步长必须为负数,否则结果是空列表。
# 索引: 0 1 2 3 4 5 6
list6 = [10, 20, 30, 40, 50, 60, 70]
list7 = list6[5:0:-1]
print(list7) # [60, 50, 40, 30, 20]
list8 =list6[5:0:-2]
print(list8) # [60, 40, 20]
# 注意:一个特殊情况:当同时省略起始索引和结束索引时,如果步长为负数,那Python会自动对调:起始位置和结束位置。
list9 = [10, 20, 30, 40, 50, 60, 70]
list99 = list9[::-1]
print(list99) # [70, 60, 50, 40, 30, 20, 10]
# 5.12 对元组进行切片
tuple1 = (10, 20, 30, 40, 50, 60, 70)
tuple2 = tuple1[0:5:1]
print(tuple2) # (10, 20, 30, 40, 50)
# 5.13 对字符串进行切片
msg16 = 'welcome to shanghai'
msg17 = msg16[0:5:1]
print(msg17) # welco
print('------------------5.1')
# 5.2 序列的其他操作-相加
# 新序列 = 序列1 + 序列2
# 注意: 两个同类型的序列才能相加。 eq: 字符串+字符串 列表+列表 元组+元组
# 字符串相加
str1 = 'hello'
str2 = 'Python'
str3 = str1 + str2
print(str3) # helloPython
# 列表相加
li1 = [10, 20, 30]
li2 = [10, 20, 40]
li3 = li1 + li2
print(li3) # [10, 20, 30, 10, 20, 40]
# 元组相加
t1 = (10, 20, 30)
t2 = (10, 20, 40)
t3 = t1 + t2
print(t3) # (10, 20, 30, 10, 20, 40)
print('------------------5.2')
# 5.3 序列的其他操作-相乘
# 新序列 = 序列 * n
# 注意: n必须是整数,不能是浮点数。
# 字符串相乘
str4 = 'hello'
str5 = str4 * 3
print(str5) # hellohellohello
# 列表相乘
li4 = [10, 20, 30, 20]
li5 = li4 * 3
print(li5) # [10, 20, 30, 20, 10, 20, 30, 20, 10, 20, 30, 20]
# 元组相乘
t4 = (10, 20, 30, 20)
t5 = t4 * 3
print(t5) # (10, 20, 30, 20, 10, 20, 30, 20, 10, 20, 30, 20)
4.2 数据容器2
目录:
6.数据容器-集合(set / frozenset)
6.1 介绍
6.2 定义有内容的(可变集合)
6.3 创建不可变集合:
6.4 定义空集合
6.5 集合嵌套
6.6 集合操作-增
6.7 集合操作-删
6.8 集合操作-改
6.9 集合操作-查
6.10 集合中常用方法
6.11 集合。数学运算
6.12 集合。循环遍历
6.13 集合。特点总结
7.数据容器-字典(dict)
7.1 介绍
7.2 字典-增删改查
7.3 字典-常用方法
7.4 字典-循环遍历
7.5 字典-特点总结
8.数据容器-总结
8.1 数据容器-通用操作
8.2 数据容器-小练习
8.3 数据容器-总结
总结2: 可变对象 和 不可变对象
python
# 目录:
# 6.数据容器-集合(set / frozenset)
# 6.1 介绍
# 6.2 定义有内容的(可变集合)
# 6.3 创建不可变集合:
# 6.4 定义空集合
# 6.5 集合嵌套
# 6.6 集合操作-增
# 6.7 集合操作-删
# 6.8 集合操作-改
# 6.9 集合操作-查
# 6.10 集合中常用方法
# 6.11 集合。数学运算
# 6.12 集合。循环遍历
# 6.13 集合。特点总结
# 7.数据容器-字典(dict)
# 7.1 介绍
# 7.2 字典-增删改查
# 7.3 字典-常用方法
# 7.4 字典-循环遍历
# 7.5 字典-特点总结
# 8.数据容器-总结
# 8.1 数据容器-通用操作
# 8.2 数据容器-小练习
# 8.3 数据容器-总结
# 总结2: 可变对象 和 不可变对象
print('------------------集合')
# 6.数据容器-集合(set / frozenset)
# 6.1 介绍
# 集合分为2种:
# 可变集合: 创建后可以增删元素。 set
# 不可变集合:创建后不可以增删元素。 frozenset
# 集合的特点:内部的元素无序(不保证顺序),不能通过下标访问元素,会自动去除重复元素。
# 可变集合: {元素0, 元素1, 元素2, 元素3,...}
# 6.2 定义有内容的(可变集合)
s1 = {10, 20, 20, 30, 40, 40, 50, 60, 60, 70, 80, 90, 100}
s2 = {'你好', 'hello', '你好', 'shanghai', '北京'}
s3 = {10, '你好', 1, True, 12.4}
print(s1, type(s1)) # {100, 70, 40, 10, 80, 50, 20, 90, 60, 30} <class 'set'>
print(s2, type(s2)) # {'shanghai', '北京', 'hello', '你好'} <class 'set'>
print(s3, type(s3)) # {1, 10, 12.4, '你好'} <class 'set'> # 1 和 True 随意保留1个
s2.add('陈振')
print(s2)
print('------------------6.2')
# 6.3 创建不可变集合: frozenset({元素0, 元素1, 元素2, 元素3,...})
s11 = frozenset({10, 20, 20, 30, 40, 40, 50, 60, 60, 70, 80, 90, 100})
s22 = frozenset({'你好', 'hello', '你好', 'shanghai', '北京'})
s33 = frozenset({10, '你好', 1, True, 12.4})
print(s11, type(s11)) # frozenset({100, 70, 40, 10, 80, 50, 20, 90, 60, 30}) <class 'frozenset'>
print(s22, type(s22)) # frozenset({'shanghai', '北京', 'hello', '你好'}) <class 'frozenset'>
print(s33, type(s33)) # frozenset({1, 10, 12.4, '你好'}) <class 'frozenset'> # 1 和 True 随意保留1个
# s22.add('陈振') # 报错: AttributeError: 'frozenset' object has no attribute 'add'
# frozenset接收的参数,可以是任意可迭代对象,但最终返回的一定是 【不可变集合】
s111 = frozenset([40, 50, 60, 60, 70, 80, 90])
s222 = frozenset((40, 50, 60, 60, 70, 80, 90))
s333 = frozenset('hello') # 把字符串中每一次字符都拿出来作为元素
print(s111, type(s111)) # frozenset({70, 40, 80, 50, 90, 60}) <class 'frozenset'>
print(s222, type(s222)) # frozenset({70, 40, 80, 50, 90, 60}) <class 'frozenset'>
print(s333, type(s333)) # frozenset({'o', 'h', 'e', 'l'}) <class 'frozenset'>
print('------------------6.3')
# 6.4 定义空集合
# 可变集合
s4 = set()
print(s4, type(s4)) # set() <class 'set'>
s5 = {} # 这样定义出来的是: 空字典
print(s5, type(s5)) # {} <class 'dict'>
# 不可变集合(一般很少这样用,因为定义不可变空集合后,不能添加元素)
s6 = frozenset()
print(s6, type(s6)) # frozenset() <class 'frozenset'>
print('------------------6.4')
# 6.5 集合嵌套
# 集合中不能嵌套【可变集合】,但是可以嵌套【不可变集合】
# 通俗的理解是:只有'不可变'的东西,才能安全的放进集合里。
# 原因:集合不支持下标,但底层依然需要给其中的每个元素,分配一个'编号',这个编号可以用来:快速定位元素,并且这个编号是 哈希值。
# 哈希值:是根据内容计算出来的。
# 内容一旦变化,哈希值就会变化,对于集合来说,元素的哈希值一旦变化,就无法再通过原来的哈希值找到这个元素。
s1 = {10, 20, 20, 30, 40, 40, 50} # 可变集合
s2 = frozenset({10, 20, 20, 30, 40, 40, 50}) # 不可变集合
l1 = [666, 777, 888] # 列表 (可变)
t1 = ('hello','world','Python') # 元组 (不可变)
# s3 = {11, 22, s1} # 报错
s4 = {11, 22, s2}
print(s4, type(s4)) # {11, 22, frozenset({50, 20, 40, 10, 30})} <class 'set'>
# s5 = {11, 22, l1} # 报错
s6 = {11, 22, t1}
print(s6, type(s6)) # {11, ('hello', 'world', 'Python'), 22} <class 'set'>
print('------------------6.5')
# 6.6 集合操作-增
# 方法1: 集合.add(元素)
# 作用:向集合中添加元素
# 返回值: 无
s1 = {10, 20, 40, 50}
s1.add(60)
print(s1) # {40, 10, 50, 20, 60}
# 方法2: 集合.update(元素)
# 作用:向集合中批量添加元素(接收可迭代对象,例如:列表,元组,集合等)
# 返回值: 无
s1 = {10, 20, 40, 50}
s1.update([60, 70]) # 列表
s1.update((80, 90)) # 元组
s1.update({100, 200})
s1.update(range(300, 305))
print(s1) # {100, 70, 40, 200, 10, 300, 301, 302, 303, 80, 304, 50, 20, 90, 60}
print('------------------6.6')
# 6.7 集合操作-删
# 方法1: 集合.remove(元素)
# 作用:从集合中移除指定元素(若元素不存在,会报错)
# 返回值: 无
s1 = {10, 20, 40, 50}
s1.remove(20)
print(s1) # {40, 10, 50}
# s1.remove(60) # 报错
# 方法2: 集合.discard(元素)
# # 作用:从集合中移除指定元素(若元素不存在,不报错)
# # 返回值: 无
s1 = {10, 20, 40, 50}
s1.discard(20)
print(s1) # {40, 10, 50}
s1.discard(60) # 不报错
# 方法3:集合.pop()
# 作用:从集合中移除一个任意元素
# 返回值;移除的那个元素
s1 = {10, 20, 40, 50}
s11 = s1.pop()
print(s11) # 40
print(s1) # {10, 20, 50}
# 方法4: 集合.clear()
# 作用: 清空集合
# 返回值:无
s1 = {10, 20, 40, 50}
s1.clear()
print(s1) # set()
print('------------------6.7')
# 6.8 集合操作-改
# 集合没有下标,也不支持replace方法,所有集合没有专门用于 '改' 的方法。
# 可以用: remove + add 的组合,来达到 '修改' 的效果。
# 需求:把集合中的 40 修改为 60
s1 = {10, 20, 40, 50}
s1.remove(40)
s1.add(60)
print(s1) # {10, 50, 20, 60}
print('------------------6.8')
# 6.9 集合操作-查
# 由于集合没有下标,也不支持切片操作,所以集合 不具备 按位置访问的能力。
# 后面我们会说到: 成员运算符(in / not in), 通过成员运算符可以判断: 某个元素是否在集合中。
s1 = {10, 20, 40, 50}
result1 = 20 in s1
print(result1) # True
result2 = 40 not in s1
print(result2) # False
print('------------------6.9')
# 6.10 集合中常用方法
# 方法1; 集合A.difference(集合B)
# 作用:找出集合A中,不同于集合B的元素。(集合A 与 集合B都不变)
# 返回值:一个新集合
s1 = {10, 20, 30, 40, 50}
s2 = {30, 40, 50, 60, 70}
r1 = s1.difference(s2)
print(s1) # {50, 20, 40, 10, 30}
print(s2) # {50, 70, 40, 60, 30}
print(r1) # {10, 20}
# 方法2; 集合A.difference_update((集合B)
# 作用:从集合A中,删除集合B中存在的元素(集合A会被修改,而集合B不会)
# 返回值:无
s1 = {10, 20, 30, 40, 50}
s2 = {30, 40, 50, 60, 70}
s1.difference_update(s2)
print(s1) # {20, 10}
print(s2) # {50, 70, 40, 60, 30}
# 方法3; 集合A.union((集合B)
# 作用:合并两个集合,集合A和集合B都不变
# 返回值:一个新集合
s1 = {10, 20, 30, 40, 50}
s2 = {30, 40, 50, 60, 70}
s3 = s1.union(s2)
print(s1) # {50, 20, 40, 10, 30}
print(s2) # {50, 70, 40, 60, 30}
print(s3) # {70, 40, 10, 50, 20, 60, 30}
# 方法4:集合A.issubset(集合B)
# 作用:判断集合A是否为集合B的子集。
# 规则:如果集合A中的所有元素,都在集合B中,那就返回True,否则返回False
# 返回值:布尔值
s1 = {10, 20, 30, 40, 50}
s2 = {30, 40, 50, 60, 70}
s3 = {30, 40, 50}
r3 = s3.issubset(s1)
print(r3) # True
r4 = s2.issubset(s1)
print(r4) # False
# 方法5:集合A.issuperset(集合B)
# 作用:判断集合A是否为集合B的超集。
# 规则:如果在集合A中,包含了集合B中所有元素,那就返回True,否则返回False
# 返回值:布尔值
s1 = {10, 20, 30, 40, 50}
s2 = {30, 40, 50, 60, 70}
s3 = {30, 40, 50}
r3 = s1.issuperset(s3)
print(r3) # True
r4 = s2.issubset(s1)
print(r4) # False
# 方法6:集合A.isdisjoint(集合B)
# 作用:判断集合A和集合B是否没有交集。
# 规则:如果没有交集,返回True. 但凡有1个公共元素,就返回False
# 返回值: 布尔值
s1 = {10, 20, 30, 40, 50}
s2 = {30, 40, 50, 60, 70}
s3 = {80, 90}
r3 = s1.isdisjoint(s3)
print(r3) # True
r4 = s2.isdisjoint(s1)
print(r4) # False
print('------------------6.10')
# 6.11 集合。数学运算
# 方法1: 集合A | 集合B 解释:并集(返回一个新集合,,包括集合 x 和 y 中所有元素)
# 方法2: 集合A & 集合B 解释:交集(只找出集合A和集合B中,共有的元素)
# 方法3: 集合A - 集合B 解释:差集(得到属于集合A,但不属于集合B的元素)
# 方法4: 集合A ^ 集合B 解释:对称差集(排除两个集合的交集,然后合并剩下的元素)
s1 = {10, 20, 30, 40, 50, 60}
s2 = {40, 50, 60, 70, 89, 90}
# 并集
r1 = s1 | s2
print(r1) # {70, 40, 10, 50, 20, 89, 90, 60, 30}
r2 = s1 & s2
print(r2) # {40, 50, 60}
r3 = s1 - s2
print(r3) # {10, 20, 30}
r4 = s1 ^ s2
print(r4) # {70, 10, 20, 89, 90, 30}
print('------------------6.11')
# 6.12 集合。循环遍历
# 集合因为没有下标,所有集合中不能使用使用while循环直接遍历,但是可以使用for循环进行遍历。
s1 = {10, 20, 30, 40, 50, 60}
# 集合不能使用while循环遍历,错误示例:
# index = 0
# while index < len(s1):
# print(index, end = ' ') # 0 1 2 3 4 5
# # print(s1[index]) # 报错
# index += 1
# 使用for循环遍历
for item in s1:
print(item, end = ' ') # 50 20 40 10 60 30
print()
print('------------------6.12')
# 6.13 集合。特点总结
# 1、无序:集合中的元素没有固定顺序,无法通过下标访问
# 2、不重复:集合会自动去重,同一个元素只会保留一份
# 3、集合分为2种:可变集合(set) 和 不可变集合(frozenset)
# 4、集合中的元素必须是不可变类型(如:数字,字符串,元组)
# 5、集合支持:并集/交集/差集/对称差集等数学操作。
# 集合是可以去重的数据容器,当只关心元素是否存在,而不在乎顺序时,首选集合。
print('------------------字典')
# 7.数据容器-字典(dict)
# 7.1 介绍
# 字典是另一种可变容器模型,且可存储任意类型对象。
# 字典的每个键值 key:value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中
# 对应关系:键(key)与 值(value)的对应关系。
# 定义有内容的字典
d3 = {'张三': 72, '李四': 22, '王五': 79}
print(d3, type(d3)) # {'张三': 72, '李四': 22, '王五': 79} <class 'dict'>
# 字典中的key不能重复,若出现重复,则后写的会覆盖之前写的。
d1 = {'张三': 72, '李四': 22, '王五': 79, '张三': 72}
print(d1) # {'张三': 72, '李四': 22, '王五': 79}
# 定义空字典
d1 = {}
d2 = dict()
print(d1, type(d1)) # {} <class 'dict'>
print(d2, type(d2)) # {} <class 'dict'>
# 字典中的key必须是不可变类型,但value可以是任意类型。
# 通俗的讲:只有不可变的东西,才能作为key
d3 = {250: 72, '李四':60, '王五':85}
print(d3, type(d3)) # {250: 72, '李四': 60, '王五': 85} <class 'dict'>
d4 = {('抽烟','喝酒'): 72, '李四':60, '王五':85}
print(d4, type(d4)) # {('抽烟', '喝酒'): 72, '李四': 60, '王五': 85} <class 'dict'>
# d5 = {['抽烟','喝酒']: 72, '李四':60, '王五':85}
# print(d5, type(d5)) # 报错: TypeError: unhashable type: 'list'
# 字典可以嵌套
stu_dict = {
20260317001: {
'name': '张三',
'age': 19,
'成绩': 99,
'爱好': ['抽烟', '喝酒', '烫头']
},
20260317002: {
'name': '李四',
'age': 21,
'成绩': 98
},
20260317003: {
'name': '王五',
'age': 17,
'成绩': 100
}
}
# {20260317001: {'name': '张三', 'age': 19, '成绩': 99, '爱好': ['抽烟', '喝酒', '烫头']}, 20260317002: {'name': '李四', 'age': 21, '成绩': 98}, 20260317003: {'name': '王五', 'age': 17, '成绩': 100}}
print(stu_dict)
print('------------------7.1')
# 7.2 字典-增删改查
# 方法1: 查询
d6 = {'张三': 72, '李四': 22, '王五': 79}
# 直接取值,若键(key)不存在,会报错。
r6 = d6['李四']
print(r6) # 22
# r7 = d6['奥特曼'] # 报错
# 安全取值,若键(key)不存在,会返回默认值(若没有设置默认值,则会返回None)
r8 = d6.get('奥特曼', '抱歉,key不存在!')
print(r8) # 抱歉,key不存在!
# 方法2:新增
d9 = {'张三': 72, '李四': 22, '王五': 79}
d9['李四'] = 222
print(d9) # {'张三': 72, '李四': 222, '王五': 79}
# 方法3:修改
d10 = {'张三': 72, '李四': 22, '王五': 79}
# 修改的写法,与新增的写法一样,若字典中有对应的key,就是修改;若没有,就是新增
d10['陈振'] = 999
print(d10) # {'张三': 72, '李四': 22, '王五': 79, '陈振': 999}
# 批量修改
d11 = {'张三': 72, '李四': 22, '王五': 79}
d11.update({'李四': 222, '王五': 799})
print(d11) # {'张三': 72, '李四': 222, '王五': 799}
# 方法4:删除
# 删除指定key多对应的那组键值对
d12 = {'张三': 72, '李四': 22, '王五': 79}
del d12['李四']
print(d12) # {'张三': 72, '王五': 79}
# 删除指定key所对应的那组键值对,并返回这个key所对应的值
d13 = {'张三': 72, '李四': 22, '王五': 79}
r13 = d13.pop('李四')
print(d13) # {'张三': 72, '王五': 79}
print(r13) # 22
# pop方法可以设置默认值
# 默认值可以保证:当删除的key不存在时,程序不会报错,并且返回这个默认值
d14 = {'张三': 72, '李四': 22, '王五': 79}
r14 = d14.pop('李四', '删除失败')
print(d14) # {'张三': 72, '王五': 79}
print(r14) # 22
r15 = d14.pop('奥特曼', '删除失败!')
print(r15) # 删除失败!
# 方法5: 清空字典
d15 = {'张三': 72, '李四': 22, '王五': 79}
r15 = d15.clear()
print(d15) # {}
print(r15) # None
print('------------------7.2')
# 7.3 字典-常用方法
# 方法1; keys方法: 用于获取字典中所有的键
d16 = {'张三': 72, '李四': 22, '王五': 79}
k16 = d16.keys()
print(k16, type(k16)) # dict_keys(['张三', '李四', '王五']) <class 'dict_keys'>
# keys方法的返回值不是list,而是一种叫做dict_keys的类型。
# dict_keys和列表相似,可以被遍历。但是 它不能通过下标访问元素。
for item in k16:
print(item, end=' ') # 张三 李四 王五
# print(k16[0]) # 报错:TypeError: 'dict_keys' object is not subscriptable
# 借助内置的list函数,可以将dict_keys 转换成 list
l16 = list(k16)
print(l16, type(l16)) # ['张三', '李四', '王五'] <class 'list'>
# print(k16[0]) # 报错:TypeError: 'dict_keys' object is not subscriptable
# 方法2:values方法: 获取字典中所有的值
# values 方法返回值类型是: dict_values ,它的特点和 dict_keys 一样
v16 = d16.values()
print(v16, type(v16)) # dict_values([72, 22, 79]) <class 'dict_values'>
li162 = list(v16)
print(li162, type(li162)) # [72, 22, 79] <class 'list'>
# 方法3:items方法: 获取字典中所有的键值对(每组键值对以 元祖 的形式呈现)
# items方法 方法返回值类型是: dict_items ,它的特点和 dict_keys 一样
i16 = d16.items()
print(i16, type(i16)) # dict_items([('张三', 72), ('李四', 22), ('王五', 79)]) <class 'dict_items'>
li163 = list(i16)
print(li163, type(li163)) # [('张三', 72), ('李四', 22), ('王五', 79)] <class 'list'>
print('------------------7.3')
# 7.4 字典-循环遍历
# 字典不能使用while循环遍历,但可以使用for循环遍历
d17 = {'张三': 72, '李四': 22, '王五': 79}
for key in d17:
print(f'{key}的成绩是{d17[key]}')
# 张三的成绩是72
# 李四的成绩是22
# 王五的成绩是79
for key in d17.keys():
print(f'{key}的成绩是{d17[key]}')
# 张三的成绩是72
# 李四的成绩是22
# 王五的成绩是79
print('------------------7.4')
# 7.5 字典-特点总结
# 1、键值对结构:字典中的数据以key: value的形式存在,每个键都对应一个值。
# 2、键唯一:字典中的键(key)不能重复,若重复则后写的会覆盖前写的。
# 3、键不可变:键必须是不可变类型(如:数字,字符串,元祖等),而值可以是任意类型。
# 4、不支持下标:字典中的元素不能通过下标取值。
# 支持增删改查,支持for循环。
# 字典是一种以 '键' 找 '值'的映射型容器,当需要唯一标识 ---> 对应信息的结构时,首选字典。
print('------------------数据容器-通用操作')
# 8.数据容器-总结
# 8.1 数据容器-通用操作
# 以下5个函数: 既能定义对应的【空容器】,又能将【其他类型】转换成对应的数据类型。
# 8.1.1、list 函数: ① 定义空列表 ② 将【可迭代对象】 转换成列表
res1 = list(range(8)) # 数字
res2 = list('hello, Python') # 字符串
# res22 = list('陈','李','王','张') # 报错:元祖不可以
res3 = list({10, 20, 30, 40}) # 集合
res41 = list({'张三': 72, '李四': 22, '王五': 79}) # 字典1
res42 = list({'张三': 72, '李四': 22, '王五': 79}.keys()) # 字典2
res43 = list({'张三': 72, '李四': 22, '王五': 79}.values()) # 字典3
res44 = list({'张三': 72, '李四': 22, '王五': 79}.items()) # 字典4
print(res1, type(res1)) # [0, 1, 2, 3, 4, 5, 6, 7] <class 'list'>
print(res2, type(res2)) # ['h', 'e', 'l', 'l', 'o', ',', ' ', 'P', 'y', 't', 'h', 'o', 'n'] <class 'list'>
print(res3, type(res3)) # [40, 10, 20, 30] <class 'list'>
print(res41, type(res41)) # ['张三', '李四', '王五'] <class 'list'>
print(res42, type(res42)) # ['张三', '李四', '王五'] <class 'list'>
print(res43, type(res43)) # [72, 22, 79] <class 'list'>
print(res44, type(res44)) # [('张三', 72), ('李四', 22), ('王五', 79)] <class 'list'>
print('------------------8.1.1')
# 8.1.2、tuple 函数: ① 定义空元祖 ② 将【可迭代对象】 转换成元组
res1 = tuple(range(8)) # 数字
res2 = tuple('hello, Python') # 字符串
# res22 = tuple('陈','李','王','张') # 报错:元祖不可以
res3 = tuple({10, 20, 30, 40}) # 集合
res41 = tuple({'张三': 72, '李四': 22, '王五': 79}) # 字典1
res42 = tuple({'张三': 72, '李四': 22, '王五': 79}.keys()) # 字典2
res43 = tuple({'张三': 72, '李四': 22, '王五': 79}.values()) # 字典3
res44 = tuple({'张三': 72, '李四': 22, '王五': 79}.items()) # 字典4
print(res1, type(res1)) # (0, 1, 2, 3, 4, 5, 6, 7) <class 'tuple'>
print(res2, type(res2)) # ('h', 'e', 'l', 'l', 'o', ',', ' ', 'P', 'y', 't', 'h', 'o', 'n') <class 'tuple'>
print(res3, type(res3)) # (40, 10, 20, 30) <class 'tuple'>
print(res41, type(res41)) # ('张三', '李四', '王五') <class 'tuple'>
print(res42, type(res42)) # ('张三', '李四', '王五') <class 'tuple'>
print(res43, type(res43)) # (72, 22, 79) <class 'tuple'>
print(res44, type(res44)) # (('张三', 72), ('李四', 22), ('王五', 79)) <class 'tuple'>
print('------------------8.1.2')
# 8.1.3、set 函数: ① 定义空集合 ② 将【可迭代对象】 转换成集合
res1 = set(range(8)) # 数字
res2 = set('hello, Python') # 字符串
# res22 = set('陈','李','王','张') # 报错:元祖不可以
res3 = set({10, 20, 30, 40}) # 集合
res41 = set({'张三': 72, '李四': 22, '王五': 79}) # 字典1
res42 = set({'张三': 72, '李四': 22, '王五': 79}.keys()) # 字典2
res43 = set({'张三': 72, '李四': 22, '王五': 79}.values()) # 字典3
res44 = set({'张三': 72, '李四': 22, '王五': 79}.items()) # 字典4
print(res1, type(res1)) # {0, 1, 2, 3, 4, 5, 6, 7} <class 'set'>
print(res2, type(res2)) # {'t', 'l', ',', 'y', 'e', 'n', 'P', ' ', 'o', 'h'} <class 'set'>
print(res3, type(res3)) # {40, 10, 20, 30} <class 'set'>
print(res41, type(res41)) # {'张三', '王五', '李四'} <class 'set'>
print(res42, type(res42)) # {'张三', '王五', '李四'} <class 'set'>
print(res43, type(res43)) # {72, 22, 79} <class 'set'>
print(res44, type(res44)) # {('王五', 79), ('李四', 22), ('张三', 72)} <class 'set'>
print('------------------8.1.3')
# 8.1.4、str 函数: ① 定义空字符串 ② 将【任意对象】 转换成字符串
res1 = str(range(8)) # 数字
res2 = str('hello, Python') # 字符串
# res22 = str('陈','李','王','张') # 报错:元祖不可以
res3 = str({10, 20, 30, 40}) # 集合
res41 = str({'张三': 72, '李四': 22, '王五': 79}) # 字典1
res42 = str({'张三': 72, '李四': 22, '王五': 79}.keys()) # 字典2
res43 = str({'张三': 72, '李四': 22, '王五': 79}.values()) # 字典3
res44 = str({'张三': 72, '李四': 22, '王五': 79}.items()) # 字典4
res5 =str(False)
res6 =str(True)
res7 =str(None)
res8 =str(100)
print(res1, type(res1)) # range(0, 8) <class 'str'>
print(res2, type(res2)) # hello, Python <class 'str'>
print(res3, type(res3)) # {40, 10, 20, 30} <class 'str'>
print(res41, type(res41)) # {'张三': 72, '李四': 22, '王五': 79} <class 'str'>
print(res42, type(res42)) # dict_keys(['张三', '李四', '王五']) <class 'str'>
print(res43, type(res43)) # dict_values([72, 22, 79]) <class 'str'>
print(res44, type(res44)) # dict_items([('张三', 72), ('李四', 22), ('王五', 79)]) <class 'str'>
print(res5, type(res5)) # False <class 'str'>
print(res6, type(res6)) # True <class 'str'>
print(res7, type(res7)) # None <class 'str'>
print(res8, type(res8)) # 100 <class 'str'>
print('------------------8.1.4')
# 8.1.5、dict 函数: ① 定义空字典 ② 将【可迭代对象】 转换成字典
# 备注:交给dict函数的内容必须是键值对才可以,否则会报错。
res1 = dict({'张三': 72, '李四': 22, '王五': 79})
res2 = dict([('张三', 72), ('李四', 22), ('王五', 79)])
res3 = dict((('张三', 72), ('李四', 22), ('王五', 79)))
res4 = dict({('张三', 72), ('李四', 22), ('王五', 79)})
print(res1, type(res1)) # {'张三': 72, '李四': 22, '王五': 79} <class 'dict'>
print(res2, type(res2)) # {'张三': 72, '李四': 22, '王五': 79} <class 'dict'>
print(res3, type(res3)) # {'张三': 72, '李四': 22, '王五': 79} <class 'dict'>
print(res4, type(res4)) # {'张三': 72, '李四': 22, '王五': 79} <class 'dict'>
print('------------------8.1.5')
# 所有的数据容器:都支持成员运算符: in / not in 作用:判断某个 '元素' 是否在容器中。
hobby = ['抽烟','喝酒','烫头','打游戏'] # 列表
nums = (10, 20, 30, 40, 50) # 元组
message = 'hello Python' # 字符串
citys = {'北京','上海','广州','深圳'} # 集合
score = {'张三': 72, '李四': 22, '王五': 79} # 字典
print('喝酒' in hobby) # True
print(20 in nums) # True
print('hel' not in message) # False
print('上海' in citys) # True
print('陈振' in score) # False
print('------------------8.1')
# 8.2 数据容器-小练习
# 练习1:水果清单
fruits = {
'苹果': 4.5,
'香蕉': 3.2,
'橙子': 5.8,
'草莓': 12.0,
'哈密瓜': 8.,
}
# 需求1:打印所有的水果
for key in fruits:
print(f'{key}:{fruits[key]}元/斤')
# 苹果:4.5元/斤
# 香蕉:3.2元/斤
# 橙子:5.8元/斤
# 草莓:12.0元/斤
# 哈密瓜:8.0元/斤
# 需求2:找到最贵的水果
maxKey = max(fruits)
print(maxKey) # 香蕉
maxValue = max(fruits.values())
print(maxValue) # 12.0
maxItems = max(fruits.items())
print(maxItems) # ('香蕉', 3.2)
# 特殊写法:
resKey = max(fruits, key = fruits.get)
print(f'最贵的水果是{resKey},价值是:{fruits[resKey]}') # 最贵的水果是草莓,价值是:12.0
print('------------------8.1.1')
# 练习2:学生成绩表
students = [
{
'name': '张三',
'scores': {'语文': 88, '数学': 92, '英语': 95}
},
{
'name': '李四',
'scores': {'语文': 75, '数学': 83, '英语': 80}
},
{
'name': '张三',
'scores': {'语文': 92, '数学': 95, '英语': 88}
}
]
# 需求1:计算每位学生的平均分
for stu in students:
# 获取当前学生的成绩列表
score_list = stu['scores'].values()
# 计算平均值
avg = sum(score_list) / len(score_list)
print(f'{stu["name"]}的平均成绩是:{avg:.1f}') # name这个版本需要使用双引号,不然报错!
# 张三的平均成绩是:91.7
# 李四的平均成绩是:79.3
# 张三的平均成绩是:91.7
# 需求2:找到总分最高的学生
def find_best():
# 记录分数最高的学生
best_students = []
# 记录最高分
best_score = 0
# 循环遍历
for student in students:
# 获取当前学生的总成绩
total = sum(student['scores'].values())
print(total)
# 当前学生的成绩,如果 > best_score,就会更新数据
if total > best_score:
best_students = [student['name']]
best_score = total
# 当前学生的成绩与最高分相同,就加入列表
elif total == best_score:
best_students.append(student['name'])
# 最高分为:275,取得最高分的学生有:['张三', '张三']
print(f'最高分为:{best_score},取得最高分的学生有:{best_students}')
find_best()
print('------------------8.1.2')
# 练习3:评论内容
comment = '这家奶茶真好喝,环境也不错,就是价格有点贵,好喝好喝好喝!强烈推荐!'
# 需求1: 统计'好喝'出现的次数
c1 = comment.count('好喝')
print(c1) # 4
# 需求2: 将字符串中的 '贵' 替换为 '略高'
c2 = comment.replace('贵', '略高')
print(c2) # 这家奶茶真好喝,环境也不错,就是价格有点略高,好喝好喝好喝!强烈推荐!
# 需求3:是否包含 '推荐' 两个字
c3 = '推荐' in comment
print(c3) # True
print('------------------8.2')
# 8.3 数据容器-总结
# 1. 有序与无序:
# 有序:列表(list)/ 元组(tuple)/ 字符串(str)-- 元素有顺序,可通过下标访问元素
# 无序:集合(set)/ 字典(dict)-- 元素没有固定位置,不能用下标访问。
# 2. 可修改
# 可变:列表(list)/ 集合(set)/ 字典(dict)-- 可以对内容进行增删改操作
# 不可变:元组(tuple)/ 字符串(str)-- 内容固定,创建后无法修改。
# 3. 可重复:
# 允许重复:列表(list)/ 元组(tuple)/ 字符串(str)
# 不允许重复:集合(set)/ 字典(dict) 备注:字典中的key是唯一的,但value可重复。
# 1. 字符串(String)
# 特性:
# 不可变序列(字符组成)。
# 有序(支持索引和切片)。
# 支持多种操作(拼接、格式化、查找等)。
# 用途:文本处理、正则匹配。
# 示例:
s = "Hello"
print(s[1:4]) # 输出: ell
# 2. 列表(List)
# 特性:
# 可变序列(可动态增删改元素)。
# 有序(通过索引访问)。
# 可嵌套(支持多维列表)。
# 用途:动态数据集合、栈/队列实现。
# 示例:
nums = [1, 2, 3]
nums.append(4) # 修改列表
print(nums) # 输出: [1, 2, 3, 4]
# 3. 元组(Tuple)
# 特性:
# 不可变序列(创建后不能修改)。
# 有序(通过索引访问)。
# 可哈希(可作为字典的键)。
# 用途:存储固定数据(如坐标、数据库记录)。
# 示例:
point = (3, 5)
print(point[0]) # 输出: 3
# 4. 集合(Set)
# 特性:
# 无序、不重复元素的集合。
# 可变(set)或不可变(frozenset)。
# 支持数学集合操作(并集、交集等)。
# 用途:去重、成员检测。
# 示例:
unique_nums = {1, 2, 2, 3}
print(unique_nums) # 输出: {1, 2, 3}
# 5. 字典(Dictionary)
# 特性:
# 键值对(key-value)结构,键必须唯一且不可变(如字符串、数字、元组)。
# 无序(Python 3.7+ 后按插入顺序保留)。
# 可变(可动态增删改键值对)。
# 用途:快速查找、映射关系、存储配置信息。
# 示例:
person = {"name": "Alice", "age": 25}
print(person["name"]) # 输出: Alice
# 总结2: 可变对象 和 不可变对象
# Python中不可变对象(Immutable)有: 特点: 创建后值不可变,任何'操作'都会生成新对象
# ① 数值类型:
# 整数 (int) : 42
# 浮点数 (float) : 3.14
# 复数 (complex) : 1+2j
# 布尔 (bool) : 是int的子类(True / False)
# ② 字符串 (str) : 'hello'
# ③ 元组 (tuple) : (1, 2, 3)
# ④ 冻结集合 (frozenset) : frozenset([1, 2])
# ⑤ 字节串 (bytes) : b'Python'
# Python中可变对象(Mutable)有: 特点: 创建后值可原地修改,内存地址不变.
# ① 列表 (list) : [1, 2, 3]
# ② 字典 (dict) : {'key': 'value'}
# ③ 集合 (set) : {1, 2, 3}
# ④ 字节数组 (bytearray) : bytearray(b'hello')
# ⑤ 自定义类实例: 用户定义的类对象(除非显式设计为不可变)
# 元组特殊性: 若元组包含可变元素(如列表),其内容仍可变.
t = (1, [1, 2])
t[1].append(3)
print(t) # (1, [1, 2, 3])
5.面向对象
目录:
1.面向对象
2 概念介绍-对象/类/实例
3 类的定义
4.创建实例
自定义方法
实例属性
类属性
实例方法
类方法
静态方法
继承
方法重写
两个常用方法
多重继承
三种访问权限
getter和setter
魔法方法(魔术方法)
object类
多态
抽象类
创建对象时内存分析
小练习-学生管理系统
python
# 目录:
# 1.面向对象
# 2 概念介绍-对象/类/实例
# 3 类的定义
# 4.创建实例
# 5. 自定义方法
# 6. 实例属性
# 7. 类属性
# 8. 实例方法
# 9. 类方法
# 10. 静态方法
# 11. 继承
# 12. 方法重写
# 13. 两个常用方法
# 14. 多重继承
# 15. 三种访问权限
# 16. getter和setter
# 17. 魔法方法(魔术方法)
# 18. object类
# 19. 多态
# 20. 抽象类
# 21. 创建对象时内存分析
# 22. 小练习-学生管理系统
from datetime import datetime
from idlelib.config import idleConf
# 1. 面向对象:
# 2 概念介绍-对象/类/实例
# 一个拥有【属性】和【行为】的个体,是构成现实世界和程序世界的基本单位。
# 万物皆对象
# 任何一个具体存在的人或物,都可以看成一个对象。
# 通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
# 1.2 面向对象:
# 一种以对象为中心去思考和组织代码的方式,它更关注: '谁来做这件事'
# 面向过程思想: 关注 '过程'
# 面向对象思想: 关注 '谁来做这件事'
# 1.3 类(class):
# 用来描述一类事务的'模板',它规定了一类事物所具有的【属性】和 【行为】。
# 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
# 1.4 实例(instance):
# 根据【类】创建出来的一个具体的【对象】,就是【实例】(实例对象)。
# 类是抽象的,实例是具体的
# 1.5 实例化:
# 根据类'制造出'对象的过程,类的具体对象。就叫实例化。+
# 1.6 实例变量:
# 在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
# 1.7 方法:
# 类中定义的函数。
# 3 类的定义
# 定义个Person类(类名通常使用: 大驼峰写法)
class Person:
# 说明: 当一个函数被定义在了函数中时,那这个函数就被成伟: 方法
# __init__方法:初始化方法。主要作用:给当前正在创建的实例对象添加属性。
# __init__方法收到的参数:当前正在创建的实例对象(self)、其他的自定义参数。
# 当我们以后编写代码去创建Person类实例的时候,Python会自动调用__init__
def __init__(self, name, age, gender):
# 给实例添加属性(语法为:self.属性么 = 值 )
self.name = name
self.age = age
self.gender =gender
# 4.创建实例
# 定义一个Person类
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# 创建Person类的实例对象。
p1 = Person('张三', 18, '男')
p2 = Person('李四', 22, '女')
# 如果直接打印一个实例的话,我们是看不到实例身上的属性
print(p1) # <__main__.Person object at 0x000001C528009C10>
print(p2) # <__main__.Person object at 0x000001C528009C50>
# 通过 点 语法可以访问或修改实例身上的属性
print(p1.name) # 张三
print(p1.age) # 18
print(p1.gender) # 男
print('_' * 20) # 打印20个 - 字符串
print(p2.name) # 李四
print(p2.age) # 22
print(p2.gender) # 女
p1.name = '张三弟弟'
print(p1.name) # 张三弟弟
# 通过 实例.__dict__ 可以查看实例身上的所有属性
print(p1.__dict__) # {'name': '张三弟弟', 'age': 18, 'gender': '男'}
print(p2.__dict__) # {'name': '李四', 'age': 22, 'gender': '女'}
# 实例创建完毕后,依然可以通过 实例.属性名 = 值 去给实例追加属性
p1.address = '上海步行街'
print(p1.__dict__) # {'name': '张三弟弟', 'age': 18, 'gender': '男', 'address': '上海步行街'}
# 通过type函数,可以查看某个实例对象,是由哪个类创建出来的
print(type(p1)) # <class '__main__.Person'>
print(type(p2)) # <class '__main__.Person'>
print('------------------4')
# 5. 自定义方法
# 定义一个Person类
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# 自定义方法 (给实例添加行为)
# speak方法收到的参数是:调用speak方法的实例对象(self)、其他参数
# speak方法只有一份,保存在Person类身上的,所有Person类的实例对象,都可以调用到speak方法
def speak(self, msg):
print(f'我叫{self.name}, 年龄是{self.age}, 性别是{self.gender},我想说:{msg}')
# 验证一下: speak方法是存在Person类身上的
print(Person.__dict__) # {'__module__': '__main__', '__init__': <function Person.__init__ at 0x000002238AC15DA0>, 'speak': <function Person.speak at 0x000002238AC15E40>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
# 创建Person类的实例对象
p1 = Person('陈振', 25, '男')
p2 = Person('闫闫', 24, '女')
# 验证一下: Person的实例对象身上是没有speak方法的
print(p1.__dict__) # {'name': '陈振', 'age': 25, 'gender': '男'}
print(p2.__dict__) # {'name': '闫闫', 'age': 24, 'gender': '女'}
# 所有的Person类的实例对象,都可以调用到speak方法
# 当执行p1.speak()方法时,查找speak方法的过程:
# 1. 实例对象自身(p1) ==>
# 2. 实例的 '缔造者' 的身上(Person)
p1.speak('好好学习') # 我叫陈振, 年龄是25, 性别是男,我想说:好好学习
p2.speak('天天向上') # 我叫闫闫, 年龄是24, 性别是女,我想说:天天向上
# 验证一下上述的查找过程
def speak():
print('把巴拉巴拉小魔仙')
p1.speak = speak
print(Person.__dict__) # {'__module__': '__main__', '__init__': <function Person.__init__ at 0x0000025D5DD15D00>, 'speak': <function Person.speak at 0x0000025D5DD15DA0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
print(p1.__dict__) # {'name': '陈振', 'age': 25, 'gender': '男', 'speak': <function speak at 0x0000025D5D8404A0>}
print(p2.__dict__) # {'name': '闫闫', 'age': 24, 'gender': '女'}
p1.speak() # 把巴拉巴拉小魔仙
print('------------------5')
# 6. 实例属性
class Person:
# 初始化方法
def __init__(self, name, age, gender):
# 通过 [实例.属性名 = 值]给实例添加的属性,就叫实例属性
# 实例属性只能通过实例访问,不能通过类访问。
# 每个实例都有自己的 【独一份的】实例属性,各个实例之间是互不干扰的
self.name = name
self.age = age
self.gender = gender
# 创建Person类的实例对象
p1 = Person('陈振', 25, '男')
p2 = Person('闫闫', 24, '女')
# 实例属性只能通过实例访问,不能通过类方法
print(p1.name) # 陈振
# print(Person.name) # 报错: AttributeError: type object 'Person' has no attribute 'name'
p1.name = '陈铮'
print(p1.name) # 陈铮
print(p2.name) # 闫闫
print('------------------6')
# 7. 类属性
class Person:
# max_age 、 planet
# 类属性可以通过类访问,也可以通过实例访问
# 类属性通常用于保存:公共数据
max_age = 120
planet = '地球'
# 初始化方法
def __init__(self, name, age, gender):
# 给实例添加属性
self.name = name
self.gender = gender
if age < self.max_age:
self.age = age
else:
print(f'年龄超过了范围,已经将年龄设置为最大值:{Person.max_age}')
self.age = Person.max_age
# 验证一下:类属性是保存在类身上的
print(Person.__dict__) # {'__module__': '__main__', 'max_age': 120, 'planet': '地球', '__init__': <function Person.__init__ at 0x0000025722AE5F80>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
# 创建Person类的实例对象
p1 = Person('陈振', 25, '男')
p2 = Person('闫闫', 24, '女')
# 验证一下:类属性可以通过类访问,也可以通过实例访问。
print(Person.max_age) # 120
print(p1.max_age) # 120 # 查找max_age的过程:1、实例自身(p1) ==》 2. 实例的'缔造者' (Person)
print(p2.max_age) # 120
# 测试一下:年龄超过范围
p3 = Person('李白', 199, '男') # 年龄超过了范围,已经将年龄设置为最大值:120
print(Person.__dict__) # {'__module__': '__main__', 'max_age': 120, 'planet': '地球', '__init__': <function Person.__init__ at 0x000001A906335F80>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
print(p1.__dict__) # {'name': '陈振', 'gender': '男', 'age': 120}
print(p2.__dict__) # {'name': '闫闫', 'gender': '女', 'age': 120}
print('------------------7')
# 8. 实例方法
class Person:
# 初始化方法(给实例添加属性)
def __init__(self, name, age, gender):
self.name = name
self.gender = gender
self.age = age
# 下面的speak方法,run方法,都保存在类身上,但他们主要提供: 实例调用,所有他们都叫:实例方法
# 自定义方法:(给实例添加行为)
def speak(self, msg):
print(f'我叫{self.name}, 年龄是{self.age}, 性别是{self.gender},我想说:{msg}')
# 自定义方法:(给实例添加行为)
def run(self, distance):
print(f'{self.name}疯狂奔跑了{distance}米')
# 创建Person类的实例对象
p1 = Person('陈振', 25, '男')
p2 = Person('闫闫', 24, '女')
print(Person.__dict__)
print(p1.__dict__)
print(p2.__dict__)
# 通过实例调用实例方法
p1.speak('你好') # 我叫陈振, 年龄是25, 性别是男,我想说:你好
p1.run(5000) # 陈振疯狂奔跑了5000米
# 通过类去调用实例方法(能调用,但不推荐!)
# Person.run(100) # 报错: TypeError: Person.run() missing 1 required positional argument: 'distance'
Person.run(p1, 3000) # 陈振疯狂奔跑了3000米
p1.run(3000) # 陈振疯狂奔跑了3000米
print('------------------8')
# 9. 类方法
class Person:
# 类属性
max_age = 120
planet = '地球'
# 初始化方法(给实例添加属性)
def __init__(self, name, age, gender):
self.name = name
self.gender = gender
self.age = age
# speak方法,run方法。他们都属于:实例方法
# 自定义方法:(给实例添加行为)
def speak(self, msg):
print(f'我叫{self.name}, 年龄是{self.age}, 性别是{self.gender},我想说:{msg}')
def run(self, distance):
print(f'{self.name}疯狂奔跑了{distance}米')
# 使用 @classmethod 装饰过的方法,就叫:类方法,类方法保存在类身上的
# 类方法收到的参数:当前类本身 (cls) 、自定义的参数。
# 因为收到了 cls 参数,所以类方法中可以访问类属性的
# 类方法通常用于实现:与类有关的逻辑,例如:操作类级别的信息、一些工厂方法
@classmethod
def change_planet(cls, value):
cls.planet = value
@classmethod
def create(cls, info_str):
# 从 info_str中获取有效信息
name, year, gender = info_str.split('-')
# 获取当前的年份
current_year = datetime.now().year
# 计算年龄
age = current_year - int(year)
# 创建爱你并返回一个Person类的实例对象
return cls(name, age, gender) # cls 相当于 Person
# 验证一下:类方法保存在类身上的
print(Person.__dict__) # {'__module__': '__main__', 'max_age': 120, 'planet': '地球', '__init__': <function Person.__init__ at 0x000001D4C2F37A60>, 'speak': <function Person.speak at 0x000001D4C2F37C40>, 'run': <function Person.run at 0x000001D4C2F37420>, 'change_planet': <classmethod(<function Person.change_planet at 0x000001D4C2F37880>)>, 'create': <classmethod(<function Person.create at 0x000001D4C2F37E20>)>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
# 类方法需要通过类调用
Person.change_planet('月球')
print(Person.__dict__) # {'__module__': '__main__', 'max_age': 120, 'planet': '月球', '__init__': <function Person.__init__ at 0x0000020C77D17BA0>, 'speak': <function Person.speak at 0x0000020C77D17380>, 'run': <function Person.run at 0x0000020C77D177E0>, 'change_planet': <classmethod(<function Person.change_planet at 0x0000020C77D17D80>)>, 'create': <classmethod(<function Person.create at 0x0000020C77D17A60>)>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
# 创建Person类的实例对象
p1 = Person('陈振', 25, '男')
p2 = Person('闫闫', 24, '女')
# 验证一下:类属性planet已经改变了
print(p1.planet) # 月球
print(p2.planet) # 月球
# 测试一下类方法-create
p33 = Person.create('林黛玉-2005-女')
print(p33.__dict__) # {'name': '林黛玉', 'gender': '女', 'age': 21}
# 注意点: 类方法,也能通过实例调用到,但是非常不推荐
p4 = p1.create('贾宝玉-2006-男')
print(p4.__dict__) # {'name': '贾宝玉', 'gender': '男', 'age': 20}
print('------------------9')
# 10. 静态方法
# 定义一个Person类
class Person:
# 初始化方法(给实例添加属性)
def __init__(self, name, age, gender):
self.name = name
self.gender = gender
self.age = age
@staticmethod
def is_audit(year):
# 获取当前的年份
current_year = datetime.now().year
# 计算年龄
age = current_year - int(year)
# 返回结果(成年True, 未成年False)
return age > 18
@staticmethod
def mask_idcard(idcard):
return idcard[:6] + '***' + idcard[-4:]
# 验证一下:静态方法也是保存在类身上的。
print(Person.__dict__) # {'__module__': '__main__', '__init__': <function Person.__init__ at 0x000002B3FF4B6CA0>, 'is_audit': <staticmethod(<function Person.is_audit at 0x000002B3FF4B6980>)>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
# 静态方法需要通过类去调用
result = Person.is_audit(2020)
print(result) # False
result2 = Person.mask_idcard('456789166945124186')
print(result2) # 456789***4186
# 注意点:通过实例也能调用到静态方法,但非常不推荐。
p1 = Person('张三', 18, '男')
result3 = p1.mask_idcard('45646465469849615694')
print(result3) # 456464***5694
print('------------------10')
# 11. 继承
class Person:
def __init__(self, name, age, gender):
self.name = name
self.gender = gender
self.age = age
def speak(self, msg):
print(f'我叫{self.name}, 年龄是{self.age}, 性别是{self.gender},我想说:{msg}')
class Student(Person):
def __init__(self, name, age, gender, stu_id, grade):
# 在子类中,有两种方式去调用父类的初始化方法,来实现对继承属性:name, age, gender 初始化操作。
# 方式1: (更推荐)
super().__init__(name, age, gender)
# 方式2
# Person.__init__(self, name, age, gender)
# 子类独有的属性,需要自己手动完成初始化
self.stu_id = stu_id
self.grade = grade
def study(self):
print(f'我叫{self.name},我在努力地学习,争取做到{self.grade}。做到年级第一名')
# 创建speak方法的过程:1、实例自身(s1) ==》 2. Student类 ==> Person类
s1 = Student('陈振', 34, '男', '20250115', '大一')
print(s1.__dict__) # {'name': '陈振', 'gender': '男', 'age': 34, 'stu_id': '20250115', 'grade': '大一'}
print(type(s1)) # <class '__main__.Student'>
# 查找speak方法的过程: 1.实例自身(s1)==> 2、Student类 ==> 3.Person类
s1.speak('hello') # 我叫陈振, 年龄是34, 性别是男,我想说:hello
print(s1.__dict__) # {'name': '陈振', 'gender': '男', 'age': 34, 'stu_id': '20250115', 'grade': '大一'}
# 查找study方法的过程: 1.实例自身(s1)==> 2、Student类 ==> 3.Person类
s1.study() # 我叫陈振,我在努力地学习,争取做到大一。做到年级第一名
print('------------------11')
# 12. 方法重写
class Person:
def __init__(self, name, age, gender):
self.name = name
self.gender = gender
self.age = age
def speak(self, msg):
print(f'我叫{self.name}, 年龄是{self.age}, 性别是{self.gender},我想说:{msg}')
class Student(Person):
def __init__(self, name, age, gender, stu_id, grade):
super().__init__(name, age, gender)
self.stu_id = stu_id
self.grade = grade
def speak(self, msg):
super().speak(msg)
print(f'我是学生,我的学号是{self.stu_id}, 我正在读{self.grade},我想说{msg}')
s1 = Student('陈振', 34, '男', '20250115', '大一')
# 我叫陈振, 年龄是34, 性别是男,我想说:好好学习
# 我是学生,我的学号是20250115, 我正在读大一,我想说好好学习
s1.speak('好好学习')
print('------------------12')
# 13. 两个常用方法
class Person:
def __init__(self, name, age, gender):
self.name = name
self.gender = gender
self.age = age
class Student(Person):
def __init__(self, name, age, gender, stu_id, grade):
super().__init__(name, age, gender)
self.stu_id = stu_id
self.grade = grade
p1 = Person('张三', 19, '男')
s1 = Student('陈振', 34, '男', '20250115', '大一')
# 方法1:isinstance(instance, Class),作用:判断某个对象是否为指定类或其子类的实例。
print(isinstance(s1, Student)) # True
print(isinstance(p1, Person)) # True
print(isinstance(s1, Person)) # True
print(isinstance(p1, Student)) # False
# 方法2:issubclass(Class1, Class2), 作用:判断某个类是另一个类的子类。
print(issubclass(Student, Person)) # True
print(issubclass(Person, Student)) # False
print('------------------13')
# 14. 多重继承
class Person:
def __init__(self, name, age, gender):
self.name = name
self.gender = gender
self.age = age
def speak(self):
print(f'我叫{self.name}, 年龄是{self.age}, 性别是{self.gender}')
class Worker:
def __init__(self, company):
self.company = company
def do_work(self):
print(f'我叫{self.company}做兼职!')
class Student(Person, Worker):
def __init__(self, name, age, gender, company, stu_id, grade):
Person.__init__(self, name, age, gender)
Worker.__init__(self, company)
self.stu_id = stu_id
self.grade = grade
def study(self):
print(f'我在努力的学生,争取做到{self.grade}年级的第一名')
s1 = Student('陈振', 34, '男', '京东', '20250115', '大一')
print(s1.__dict__) # {'name': '陈振', 'gender': '男', 'age': 34, 'company': '京东', 'stu_id': '20250115', 'grade': '大一'}
s1.speak() # 我叫陈振, 年龄是34, 性别是男
s1.do_work() # 我叫京东做兼职!
s1.study() # 我在努力的学生,争取做到大一年级的第一名
# 类的__mro__属性:用于记录属性和方法的查找顺序。
# 通过实例去查找属性或方法时,会先在实例身上去查找,如果没有,就按照__mro__记录的顺序去查找。
print(Student.__mro__) # (<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Worker'>, <class 'object'>)
print('------------------14')
# 15. 三种访问权限
class Person:
def __init__(self, name, age, idcard):
self.name = name # 公共属性:当前类中,子类中,类外部,都可以访问
self._age = age # 受保护的属性:当前类中,子类中,都可以访问。
self.__idcard = idcard # 私有属性: 仅能在当前类中访问
def speak(self):
print(f'我叫:{self.name},年龄:{self._age}身份证{self.__idcard}')
class Student(Person):
def hello(self):
print(f'我是学生({self.name}-{self.age})')
p1 = Person('张三', 18, '4564641631456413')
print(p1.name)
# 在类的外部,如果强制访问【受保护的属性】也能访问,但十分不推荐!ddddddddddddd
print(p1._age) # 18
# 在累的外部,如果强制访问【私有属性】不能访问到,而且会报错!
# print(p1.__idcard) # 报错
# Python底层是通过重命名的方式,实现私有属性的。
print(p1.__dict__) # {'name': '张三', '_age': 18, '_Person__idcard': '4564641631456413'}
# print(p1._Person_idcard)
print('------------------15')
# 16. getter和setter
class Person:
def __init__(self, name, age, idcard):
self.name = name # 公共属性:当前类中,子类中,类外部,都可以访问
self._age = age # 受保护的属性:当前类中,子类中,都可以访问。
self.__idcard = idcard # 私有属性: 仅能在当前类中访问
# 注册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 < 188:
self._age = value
else:
print('年龄非法,修改失败!')
@property
def idcard(self):
# return self.__idcard
return self.__idcard[:6] + '******' + self.__idcard[-4:]
@idcard.setter
def idcard(self, value):
print('抱歉,身份证号码不允许修改,如有疑问,请联系管理员!')
p1 = Person('张三', 18, '4564641631456413')
print(p1.name) # 张三
print(p1.age) # 18
p1.age = 122
print(p1.age) # 122
print(p1.idcard) # 456464******6413
p1.idcard = '5645131683161563' # # 抱歉,身份证号码不允许修改,如有疑问,请联系管理员!
print(p1.idcard) # 456464******6413
print('------------------16')
# 17. 魔法方法(魔术方法)
# 概念:以 __xxx__命名的特殊方法(双划线开头和结尾)
# 特点: 不需要我们手动调,我们只要准备好这些方法,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):
return f'{self.name}-{self.age}-{self.gender}'
# 当执行len(Person的实例对象)时调用
def __len__(self):
return len(self.__dict__)
# 当执行Person实例对象1 < Person实例对象2时调用
def __lt__(self, other):
return self.age < other.age
# 当执行Person实例对象1 > Person实例对象2时调用
def __gt__(self, other):
return self.age > other.age
# 当执行Person实例对象1 == Person实例对象2时调用
def __eq__(self, other):
return self.__dict__ == other.__dict__
# 当访问Person实例对象身上不存在的属性时调用
def __getattr__(self, item):
return f'你访问的{item}属性不存在'
p1 = Person('陈振', 19, '男')
p3 = Person('陈振', 19, '男')
p2 = Person('闫闫', 18, '女')
print(p1) # 陈振-19-男
print(p2) # 闫闫-18-女
print(p1.__dict__)
res = len(p1)
print(res)
print(p1 < p2) # False
print(p1.age < p2.age) # False
print(p1 > p2) # True
print(p1 == p3) # True # 原本比较的地址值是否相等。两个对象的地址值不一致返回False, __eq__重写了比较的内容
print(p1.address) # 你访问的address属性不存在
print('------------------17')
# 18. object类
# Python中,所有的类都继承了object类,即:object类是所有类的顶层父类。
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# 验证一下:所有的类都继承了object类
print(issubclass(Person, object)) # True
print(issubclass(int, object)) # True
print(issubclass(str, object)) # True
print(issubclass(list, object)) # True
print(issubclass(bool, object)) # True
print(issubclass(tuple, object)) # True
# 因为object 是所有类的父类,所以Python中的所有对象,都间接是 object 类的实例。
p1 = Person('张收纳', 18,'男')
print(isinstance(p1, object)) # True
print(isinstance(100, object)) # True
print(isinstance('hello', object)) # True5
print(isinstance(True, object)) # True-
print(isinstance(None, object)) # True
print(isinstance([10, 20, 30], object)) # True
print(isinstance({'吃饭','睡觉'}, object)) # True
# 所有对象都继承了 object 类所提供的: 各种属性和方法,从而保证了每个对象都具备统一的基本能力。
for key in object.__dict__:
print(key) # __str__ ...
p2 = Person('李四', 19,'女')
print(p2.__dict__) # {'name': '李四', 'age': 19, 'gender': '女'}
print(dir(p2)) # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'gender', 'name']
print(p2.__str__()) # <__main__.Person object at 0x0000024C6CE25FD0>
print(p2) # <__main__.Person object at 0x0000024C6CE25FD0>
print('------------------18')
# 19. 多态
# 多态的概念:同一个方法名,在不同的对象上调用时,能呈现出不同的行为。
# Python中支持:标准多态、 鸭子多态
# 19.1 标准多态
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) # 哼哼哼 # 此行代码如果在其他语言中会报错。 Python不会报错,不推荐这样写!
# 19.2 鸭子多态
# 核心理念:如果一个东西看起来像鸭子,叫起来也像鸭子,那它就是鸭子。
# 鸭子类型是一种编程风格: 它不检查对象的类型,只关注对象能否'做某件事'(是否有对于的方法)
class Dog(Animal):
def speak(self):
print('汪汪汪')
class Cat(Animal):
def speak(self):
print('喵喵喵')
class Pig:
def speak(self):
print('哼哼哼')
class Fish:
def speak(self):
print('咕噜')
class Computer:
def speak(self):
print('吱吱吱')
def make_sound(animal): # 类型注解
# 多条的体现
animal.speak()
# 创建实例对象
d1 = Dog()
c1 = Cat()
p1 = Pig()
f1 = Fish()
cm1 = Computer()
make_sound(d1) # 汪汪汪
make_sound(c1) # 喵喵喵
make_sound(p1) # 哼哼哼
make_sound(f1) # 咕噜
make_sound(cm1) # 吱吱吱
print('------------------19')
# 20. 抽象类
# 【抽象类】是一种不能直接实例化的类,它通常作废'规范',让子类去继承,并实现其中定义的【抽象方法】
from abc import ABC, abstractmethod
# MustRun类一旦继承了ABC类,那么MustRun类就是抽象类了。
class MustRun(ABC):
@abstractmethod
def run(self):
pass
def speak(self):
print(f'你好,我叫:{self.name}')
class Person(MustRun):
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def run(self):
print(f'我叫{self.name},我在努力的奔跑!')
p1 = Person('陈振', 18, '男')
p1.run() # 我叫陈振,我在努力的奔跑!
print('------------------20')
# 21. 创建对象时内存分析
# 创建不可变对象时:(int float bool str tuple frozenset None)
# ① 创建后值不可修改,每次 '修改' 实际会生产新对象。
# ② Python会缓存部分不可变对象(如:小整数,短字符串)。复用相同的内存地址
# 创建可变对象时:(list dict set 自定义类的实例对象)
# ① 值可原地修改,内存地址不会变
# ② 每次创建新对象时分配独立内存,即使内容相同。
a = 666
print(id(a)) # id() 内存地址 # 2237181901712
print(hex(id(a))) # hex() 16进制地址 # 0x208e26ebb90
b = a
print(id(b)) # 2237181901712
print(hex(id(b))) # 0x208e26ebb90
a = 888 # int类型是不可变对象
print(a) # 888
print(id(a)) # 2237181893904 a内存地址变了
print(b) # 666
print(id(b)) # 2237181901712 b内存地址没变
del b
# Python中常见的不可变对象有:int float bool str tuple frozenset None
# Python中常见的可变对象有: list dict set 自定义类的实例对象
stu_list = ['张三', '李四', '王五']
print(id(stu_list)) # 1764059403328
print(id(stu_list[0])) # 1764058754256
stu_list[0] = '张三2'
print(id(stu_list)) # 1764059403328
print(id(stu_list[0])) # 1764058755504
print('------------------21')
# 22. 小练习-学生管理系统
# 需求: 学生管理系统
# 包含:1.添加学生 2.删除学生 3.查看所有学生 4, 录入成绩 5.退出 请输入操作序号
class Person():
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Student(Person):
count = 0
def __init__(self, name, age, gender):
super().__init__(name, age, gender)
Student.count += 1
self.stu_id = f'{datetime.now().year}{Student.count:03d}'
self.scores = {} # {'数学': 90, '语文': 80, '英语': 70}
# 给当前学生添加成绩
def add_score(self, subject, score):
self.scores[subject] = score
# 计算平均分
def calcu_avg(self):
if self.scores:
return sum(self.scores.values()) / len(self.scores)
else:
return 0
# 魔法方法
def __str__(self):
return f'{self.name}-{self.age}-{self.gender},成绩是:{self.scores}, 平均分{self.calcu_avg():.1f}'
s1 = Student('陈1', 18, '男')
s2 = Student('陈2', 19, '女')
s3 = Student('陈3', 20, '男')
print(s1.__dict__) # {'name': '陈1', 'age': 18, 'gender': '男', 'stu_id': '2026001', 'scores': {}}
print(s2.__dict__) # {'name': '陈2', 'age': 19, 'gender': '女', 'stu_id': '2026002', 'scores': {}}
print(s3.__dict__) # {'name': '陈3', 'age': 20, 'gender': '男', 'stu_id': '2026003', 'scores': {}}
s4 = Student('陈1', 18, '男')
s4.add_score('数学', 90)
s4.add_score('语文', 80)
s4.add_score('英语', 70)
r4 = s4.calcu_avg()
print(f'平均成绩为:{r4:.1f}')
# 打印s4会调用 __str__ 方法
print(s4) # 陈1-18-男,成绩是:{'数学': 90, '语文': 80, '英语': 70}, 平均分80.0
class Manager:
def __init__(self):
self.stu_list = []
# 添加学生
def add_student(self):
name = input('请输入姓名:')
age = input('请输入年龄:')
gender = input('请输入性别:')
stu = Student(name, age, gender)
self.stu_list.append(stu)
print(f'添加成功!学号是:{stu.stu_id}')
# 删除学生
def del_student(self):
sid = input('请输入学号:')
target = None
for stu in self.stu_list:
if stu.stu_id == sid:
target = stu
if target:
self.stu_list.remove(target)
print('删除成功!')
else:
print('学号有误,删除失效!')
# 展示所有学生信息
def show_all_student(self):
if self.stu_list:
for stu in self.stu_list:
print(stu)
else:
print('暂无学生数据')
# 给指定学生设置成绩
def set_score(self):
sid = input('请输入学号:')
for stu in self.stu_list:
if stu.stu_id == sid:
score_str = input('请输入成绩(学科-分数,学科-分数)')
score_list = score_str.replace(',', ',').split(',')
for item in score_list:
subject, score = item.split('-')
subject = subject.strip()
score = float(score.strip())
stu.add_score(subject, score)
print('添加成功!')
return
print('学号有误!')
#
def run(self):
while True:
print('*************学生管理系统***********************')
print('1. 添加学生')
print('2. 删除学生')
print('3. 查询所有学生')
print('4. 录入成绩')
print('5. 退出')
chocie = input('请输入操作编号:')
if chocie == '1':
self.add_student()
elif chocie == '2':
self.del_student()
elif chocie == '3':
self.show_all_student()
elif chocie == '4':
self.set_score()
elif chocie == '5':
print('再见')
break
else:
print('输入有误')
# 运行系统
m1 = Manager()
m1.run()
6. 函数进阶
目录:
函数进阶内容
1.重新认识函数
函数的多返回值 & 参数的打包与解包
高阶函数
条件表达式
匿名函数
数据处理函数
6.1 map 函数
6.2 filter函数
6.3 sorted函数
6.4 reduce函数
列表推导式
常用内置函数
赋值 和 浅拷贝 和 深拷贝
四种作用域 LEGB
闭包
12.装饰器
12.1 函数装饰器
12.2 类装饰器
- 类型注解
13.1 变量类型注解
13.2 函数类型注解
python
# 目录:
# 函数进阶内容
# 1.重新认识函数
# 2. 函数的多返回值 & 参数的打包与解包
# 3. 高阶函数
# 4. 条件表达式
# 5. 匿名函数
# 6. 数据处理函数
# 6.1 map 函数
# 6.2 filter函数
# 6.3 sorted函数
# 6.4 reduce函数
# 7. 列表推导式
# 8. 常用内置函数
# 9. 赋值 和 浅拷贝 和 深拷贝
# 10. 四种作用域 LEGB
# 11. 闭包
# 12.装饰器
# 12.1 函数装饰器
# 12.2 类装饰器
# 13. 类型注解
# 13.1 变量类型注解
# 13.2 函数类型注解
# 1.重新认识函数
# 1.1 函数也是对象
a1 = 100 # int类的实例对象
a2 = 'hello' # str类的实例对象
a3 = [10, 20, 30] # list类的实例对象
def welcome():
print('hello python') # welcome函数是function类的实例对象
print(type(a1)) # <class 'int'>
print(type(a2)) # <class 'str'>
print(type(a3)) # <class 'list'>
print(type(welcome)) # <class 'function'>
# 1.2 函数可以动态添加属性
def welcome():
print('hello python')
welcome.desc = '这是一个打招呼的函数'
welcome.version = '1.0.0'
print(welcome.desc) # 这是一个打招呼的函数
print(welcome.version) # 1.0.0
# 1.3. 函数可以赋值给变量
def welcome():
print('hello python')
welcome.desc = '这是一个打招呼的函数'
welcome.version = '1.0.0'
say_hello = welcome
say_hello()
print(say_hello.desc) # 这是一个打招呼的函数
print(say_hello.version) # 1.0.0
# 1.4 可变参数 vs 不可变参数
# 不可变参数
a = 666
def welcome(data):
print('data修改前', data, id(data))
data = 888
print('data修改后', data, id(data))
print('函数调用前', a, id(a)) # 666
welcome(a) # 666 888
print('函数调用后', a, id(a)) # 666 # int类型是不可变对象。 data是888
# 可变对象
a = [10, 20, 30]
def welcome(data):
print('data修改前', data, id(data))
data[2] = 99
print('data修改后', data, id(data))
print('函数调用前', a, id(a)) # [10, 20, 30]
welcome(a) # [10, 20, 30] [10, 20, 99]
print('函数调用后', a, id(a)) # [10, 20, 99] # a类型是可变对象。引用地址没变
# 1.5 函数也可以作为参数
def welcome():
print('hello')
def caller(f):
print('caller函数调用了')
f()
caller(welcome)
# caller函数调用了
# hello
# 1.6 函数也可以作为返回值
def welcome():
print('hello')
def show_msg(msg):
print(msg)
return show_msg
result = welcome()
result('尚硅谷')
# hello
# 尚硅谷
print('------------------1')
# 2. 函数的多返回值 & 参数的打包与解包
# 2.1 函数的多返回值
def calculate(x, y):
res1 = x + y
res2 = x - y
return res1, res2
result = calculate(1, 2)
print(result) # (3, -1)
r1, r2 = calculate(1, 2)
print(r1, r2) # 3 -1
# 2.2 参数的打包与解包
# ①. 打包接收参数:
# *args : 打包所有的位置参数(会形成一个元组)
# **kwargs : 打包所有的关键字参数(会形成一个字典)
def show_info(*args, **kwargs):
print(args)
print(kwargs)
# (10, 20, 30)
# {'name': '张三', 'age': 18, 'gender': '男'}
show_info(10, 20, 30, name = '张三', age = 18, gender = '男')
# ②.解包传递参数
# *变量名 :将元组拆解成一个一个独立的位置参数。
# **变量名: 将字典拆解一个一个 key = value 形式的关键字参数。
def show_info(num1, num2, num3, name, age, gender):
print(num1, num2, num3)
print(name, age, gender)
nums = [1, 2, 3]
person = {'name':'张三', 'age':18, 'gender':'男'}
# 1 2 3
# 张三 18 男
show_info(*nums, **person)
# ③.打包接收参数 和 解包传递参数,一起使用。
def show_info(*args, **kwargs):
print(args)
print(kwargs)
nums = [1, 2, 3]
person = {'name':'张三', 'age':18, 'gender':'男'}
# (1, 2, 3)
# {'name': '张三', 'age': 18, 'gender': '男'}
show_info(*nums, **person)
print('------------------2')
# 3. 高阶函数
# 当一个函数的 【参数是函数】 或 【返回值是函数】那该函数就是 【高阶函数】
# 高阶函数的意义:
# ① 代码复用性高:可以把行为 '独立出去', 传入不同函数实现不同逻辑
# ② 能让函数更灵活,更通用
# ③ 高阶函数是: 装饰器,闭包的基础(后续讲)
def info(msg):
print('[提示]' + msg)
def warn(msg):
print('[警告]' + msg)
def error(msg):
print('[错误]' + msg)
def log(func, text):
func(text)
log(info, '文件保存成功!') # [提示]文件保存成功!
log(warn, '磁盘空间不足!') # [警告]磁盘空间不足!
log(error, '该用户不存在!') # [错误]该用户不存在!
print('------------------3')
# 4. 条件表达式
# 表达式: 执行后能得到值的代码,就是表达式(表达式最终会形成一个值,可以写在任何需要值的地方)
a1 = 3 + 5
a2 = 'abc' * 3
print(5 > 3)
int('y' in 'Python')
a5 = len('hello')
# 条件表达式:根据条件的真假,在两个值中二选一的表达式(又称: 三元表达式、三目运算符)。
age = 21
# 传统的if-else去写
if age >= 18:
text = '成年'
else:
text = '未成年'
print(text)
# 条件表达式去写: 值1 if 条件 else 值2
text = '成年' if age >= 18 else '未成年'
print(text)
print('------------------4')
# 5. 匿名函数
# 概念:所谓【匿名函数】,就是没有名字的函数,它无需使用 def 关键字去定义。
# 语法: Python中使用 lambda 关键字去定义【匿名函数】。
# 格式为: lambda arguments:expression
# lambda是 Python 的关键字,用于定义 lambda 函数。
# arguments 是参数列表,可以包含零个或多个参数,但必须在冒号(:)前指定。
# expression 是一个表达式,用于计算并返回函数的结果。
# 使用场景:当一个函数只用一次,只做一点点小事,使用匿名函数会更简洁。
# 使用普通函数实现计算效果。
# def add(x, y):
# return x + y
#
# def sub(x, y):
# return x - y
#
# def cal(func, a, b):
# print(f'计算结果为:{func(a, b)}')
#
# cal(add, 30 ,20) # 计算结果为:50
# cal(sub, 30 ,20) # 计算结果为:10
# 匿名函数 示例
add1 = lambda x, y : x + y
add2 = lambda x : x + x
add3 = lambda: '我是add3函数'
result1 = add1(30, 10)
result2 = add2(30)
result3 = add3()
print(result1, result2, result3) # 40 60 我是add3函数
# 改造: 使用普通函数实现计算效果。
add = lambda x, y : x + y
sub = lambda x, y : x - y
cal = lambda func, a, b : print(f'计算结果为:{func(a, b)}')
cal(add, 1 , 2 ) # 计算结果为:3
cal(sub, 1 , 2 ) # 计算结果为:-1
def cal1(func, a, b):
print(f'计算结果为:{func(a, b)}')
cal1(add, 3, 5) # 计算结果为:8
cal1(sub, 3, 5) # 计算结果为:-2
cal1(lambda x, y: x + y, 30, 10) # 计算结果为:40
cal1(lambda x, y: x - y, 30, 10) # 计算结果为:20
# 注意点:
# 1. 只能写一行,不能写多行代码
# 2. 不能写代码块 (if, for, while)
# 3. 冒号右边必须是表达式,且只能写一个表达式。
# 4. 表达式结果自动作为返回值。
# 三元表达式
is_adult = '成年' if age >= 18 else '未成年'
# lambda表达式
is_adult1 = lambda age: '成年' if age >= 18 else '未成年'
print(is_adult1(19)) # 成年
print(is_adult1(14)) # 未成年
print('------------------5')
# 6. 数据处理函数
# 6.1 map 函数
# 对一组刷数据中的每一个元素,统一执行某种操作(加工),并生成一组新数据。不改变原数据。
# 语法: map(操作函数, 可迭代对象)
# ① 统一数据处理
nums = [1, 2, 3]
def double(x):
return x * 10
# map函数返回值是一个迭代器对象,需要我们手动去遍历,或者手动转换类型。
result = map(double, nums)
for item in result:
print(item, end= ' ') # 10 20 30
# 转换成list 列表
print(list(result)) # 实际会打印 [] 不打印 [10, 20, 30]的原因:
# 在Python中, map对象是一个迭代器(Iterator),它的特点是: 只能遍历一次。 当第一次通过for循环遍历result后,
# 迭代器已经到达末尾,此时再次调用 list(result) 会得到一个空列表。
# 使用匿名函数改造
result = map(lambda x: x * 2, nums)
print(list(result)) # [2, 4, 6]
print(nums) # [1, 2, 3] 为改变原来的数据。
# ② 字符串转换
names = ('Python', 'Java', 'JS') # 元组
result = map(lambda x : x.upper(), names)
print(tuple(result)) # 元组: ('PYTHON', 'JAVA', 'JS')
# print(list(result)) # 列表: ['PYTHON', 'JAVA', 'JS']
# print(set(result)) # 集合:不保证顺序 {'JS', 'JAVA', 'PYTHON'}
print(names) # ('Python', 'Java', 'JS')
# ③ 类型转换
str_number = {'1', '2', '3'}
result = map(int, str_number) # result = map(int, str_number) 直接使用int()作为映射函数, 结果与下面lambda相同
# result = map(lambda x: int(x), str_number)
print(set(result)) # {1, 2, 3}
# map函数注意点:
# 1、延迟执行: map不会立刻计算,只有在 '需要结果'时才执行计算。
# 2、返回的是迭代器对象,且一旦遍历完成,就会被 '耗尽'
# 3、map不会影响元素数量。只会对各个原始的元素做操作。
print('------------------6.1')
# 6.2 filter函数
# 从一组数据中,筛选出符合条件的元素(过滤),并组成一组新数据。不改变原数据。
# 语法格式: filter(过滤函数, 可迭代对象)
# ① 筛选 数值
nums = [1, 2, 3, 4, 5]
result = filter(lambda x:x > 3, nums)
print(list(result)) # [4, 5]
print(nums) # [1, 2, 3, 4, 5] 原有数据不变
# ② 筛选 成年人
persons = [
{'name':'陈1', 'age': 15, 'gender': '男'},
{'name':'陈2', 'age': 20, 'gender': '女'},
{'name':'陈3', 'age': 18, 'gender': '男'},
{'name':'陈4', 'age': 12, 'gender': '女'},
{'name':'陈5', 'age': 27, 'gender': '男'}
]
result = filter(lambda p: p['age'] >= 18, persons)
print(tuple(result)) # ({'name': '陈2', 'age': 20, 'gender': '女'}, {'name': '陈3', 'age': 18, 'gender': '男'}, {'name': '陈5', 'age': 27, 'gender': '男'})
# ③ 过滤 非法字符串
names = ['张三', '','李四', None, '王五']
result = filter(lambda n: n, names) # 梳理下: 张三进入转为bool值为 'True' 保留。 但是: '' 和 None转为 bool 为 'False' ,被过滤掉了
print(tuple(result)) # ('张三', '李四', '王五')
print(tuple(result)) # ()
# filter函数注意点:
# 1、延迟执行:filter不会立刻筛选,只有在 '需要结果' 时,才执行。
# 2、返回的是迭代器对象,且一旦遍历完成就会被 '耗尽'
# 3、filter可能会影响元素数量。
# filter函数的特殊用法:
# 如果不传递过滤函数,那么会自动过滤掉 '假值'
datas = [0, 1, '', 'hello', None, [], {}, (), 5]
result = filter(None, datas)
print(list(result)) # [1, 'hello', 5]
print('------------------6.2')
# 6.3 sorted函数
# 对一组数据进行排序,返回一组新数据。
# 语法格式L sorted(可迭代对象, key = xxx, reverse = xxx)
# ① 数字排序
nums = [30, 40, 20, 10]
r = sorted(nums)
print(r) # [10, 20, 30, 40]
r1 = sorted(nums, reverse=True)
print(r1) # [40, 30, 20, 10]
# ② 按照字符串的长度去排序
names = ['python', 'sql', 'java']
r3 = sorted(names, key=len, reverse=False)
print(r3) # ['sql', 'java', 'python']
r4 = sorted(names, key=len, reverse=True)
print(r4) # ['python', 'java', 'sql']
r5 = sorted(names, key=lambda x:len(x))
print(r5) # ['sql', 'java', 'python']
# ③ 根据字典中的某个字段进行排序
persons = [
{'name':'陈1', 'age': 15, 'gender': '男'},
{'name':'陈2', 'age': 20, 'gender': '女'},
{'name':'陈3', 'age': 18, 'gender': '男'},
{'name':'陈4', 'age': 12, 'gender': '女'},
{'name':'陈5', 'age': 27, 'gender': '男'}
]
p1 = sorted(persons, key = lambda x:x['age'], reverse = False)
print(p1) # [{'name': '陈4', 'age': 12, 'gender': '女'}, {'name': '陈1', 'age': 15, 'gender': '男'}, {'name': '陈3', 'age': 18, 'gender': '男'}, {'name': '陈2', 'age': 20, 'gender': '女'}, {'name': '陈5', 'age': 27, 'gender': '男'}]
# max函数,min函数,也可以传递key参数,用于设置筛选依据
m1 = max(persons, key = lambda x:x['age'])
print(m1) # {'name': '陈5', 'age': 27, 'gender': '男'}
mi1 = min(persons, key = lambda x:x['age'])
print(mi1) # {'name': '陈4', 'age': 12, 'gender': '女'}
print('------------------6.3')
# 6.4 reduce函数
# 将一组数据不断 '合并', 最终归并成一个结果。
# 语法格式: reduce(合并函数, 可迭代对象,初始值)
# 备注:reduce函数需要从 functools 模块中引入才能使用。
# 从functools模块中引入 reduce
from functools import reduce
# ① 数值统计
nums = [1, 2, 3, 4, 5]
result = reduce(lambda x,y: x + y, nums, 10)
print(result) # 25
# ② 字符串拼接
str_list = ['ab', 'cd', 'ef']
s = reduce(lambda x, y: x +y, str_list)
print(s) # abcdef
print('------------------6')
# 7. 列表推导式
# 定义: 用一条简洁语句,从可迭代对象中,生成新列表的语法结构。
# 备注:列表推导式本质是对 for 循环 + append() 的一种简写形式。
# 语法格式: [表达式 for 变量 in 可迭代对象]
# 7.1 列表推导式 最常用
# ① 需求:让列表中每个元素,都变为原来的2倍, 得到是一个新的列表。
# 方式1:用map函数
nums = [1, 2, 3, 4, 5]
r = map(lambda x: x * 2, nums)
print(list(r)) # [2, 4, 6, 8, 10]
print(nums) # [1, 2, 3, 4, 5]
# 方式2:用for循环 + append
r = []
for item in nums:
r.append(item * 2 )
print(r) # [2, 4, 6, 8, 10]
# 方式3:用列表推导式
r1 = [n * 2 for n in nums]
print(r1) # [2, 4, 6, 8, 10]
# ② 带条件的列表推导式
r2 = [n * 10 for n in nums if n >2]
print(r2) # [30, 40, 50]
# 7.2 字典推导式
names = ['陈1', '陈2', '陈3']
scores = [70, 80, 90]
r3 = {names[i]:scores[i] for i in range(len(names))}
print(r3) # {'陈1': 70, '陈2': 80, '陈3': 90}
# 7.3 集合推导式
names = {'陈1', '陈2', '陈3'}
r4 = { i + '!' for i in names}
print(r4) # {'陈3!', '陈2!', '陈1!'}
# 注意:Python中没有元组推导式,下面这种写法叫: 生成器(后面讲)
names = ('陈1', '陈2', '陈3')
r5 = ( i+'!' for i in names)
print(r5) # <generator object <genexpr> at 0x0000028FD9AAB6B0>
print('------------------7')
# 8. 常用内置函数
# 8.1 输入和输出
# ① print() : 输出指定内容
# 完整参数: print(*object, sep=' ', end='\n', file=sys.stdout, flush=False):
# 参数详解:
# 1. objects ; 要输出的内容
# 2. sep : 分割符
# 3. end : 结束符
# 4. file : 输出位置
# 5. flush : 是否立即刷新
# f = open('a.txt','w', encoding='utf-8')
# print(10, 20, 30, 40, sep='-', end = '!', file = f) # a.txt文件中输入 10-20-30-40!
import time
# 第一种进度条
print('加载中', end='')
for index in range(5):
print(',', end='', flush=True)
time.sleep(0.01)
print('完成!', end='')
# 输出: 加载中,,,,,完成!
print()
# 第二种进度条
for index in range(1, 101):
print(f'\r已加载{index}%', end= '', flush=True)
time.sleep(0.01)
# ② input() : 获取用户输入
# 8.2 类型转换
# int() : 转为整数
# float() : 转为浮点数
# str() : 转为字符串
# bool : 转为布尔值
# list() : 转为列表
# tuple() : 转为元组
# set() : 转为集合
# dict() : 转为字典
# 8.3 数学相关
# abs() : 取绝对值
print(abs(-9)) # 9
print(abs(-2.5)) # 2.5
print(abs(3 - 5 )) # 2
# round : 四舍五入
# 注意: round函数的四舍五入,是银行家舍入法: 小于5就舍, 大于5就入, 等于5看奇偶(奇入偶舍) (为了数据平衡)
print(round(3.4)) # 3
print(round(4.6)) # 5
print(round(6.5)) # 6
print(round(7.5)) # 8
# pow() : 次方
print(pow(2, 3)) # 8 (2的3次方)
print(pow(2, -1)) # 0,5 (2的-1次方)
print(pow(2, 0.5)) # 1.4142135623730951 (2的开平方)
print(pow(2, 3, 5)) # 3 (2的3次方对5取模)
# divmod() : 商和余数
# max() : 最大值(支持 key 函数)
# min() : 最小值(支持 key 函数)
# sum() : 求和
# map() : 加工一组数据
# filter() : 按条件过滤数据(支持 key 函数)
# reduce() : 合并计算(需导入 functools)
# sorted() : 排序 (支持 key 函数)
# 8.4 数据容器相关
# len() : 获取容器内元素的个数
# range() : 生成一个数字序列(可用于循环)
for index in range(0, 10, 2): # 2 为步长
print(index, end= ' ') # 0 2 4 6 8
# enumerate() : 给序列添加索引
# zip() : 将多个序列一一配对
names = ('陈1', '陈2', '陈3')
scores = [70, 80, 90]
r = zip(names, scores)
for index in r:
print(index, end= ' ') # ('陈1', 70) ('陈2', 80) ('陈3', 90)
# 8.5 类型判断与对象相关
# type() : 查看类型
# isinstance() : 判断类型
# issubclass() : 判断两个类的继承关系
# id() ; 查看对象的内存地址
# 8.6 逻辑判断相关
# all() : 全为 真 返回 True
l1 = [10, '陈振', {1, 2, 3}, -9]
print(all(l1)) # True
# ang() : 有一个为真即可
l2 = [0, '', None, False, 10]
print(any(l2)) # True
# 8.7 字符串相关
# ord() : 获取字符串的 Unicode编码值
# chr() : 将 Unicode编码值转为字符串
print('------------------8')
# 9. 赋值 和 浅拷贝 和 深拷贝
# ① 赋值 =
# 解释: 赋值操作只是创建了一个新的引用,指向同一个对象.
# 特点:
# 1.新变量和原变量指向了同一个内存地址.
# 2.修改其中一个会影响另一个
# 3.对于可变对象(列表,字典,集合等)尤其需要注意
a = [1, 2, [3, 4]]
b = a # 赋值操作
a[0] = 10
print(a) # 输出: [10, 2, [3, 4]]
print(b) # 输出: [10, 2, [3, 4]] - b也跟着改变了
# ② 浅拷贝 copy (Shallow Copy)
# 浅拷贝会创建一个新对象(顶层容器),但嵌套对象(子对象)的引用保持不变.
# 新对象与原对象共享子对象的内存地址.
# 修改子对象的值会影响原对象, 但修改顶层容器的引用不会影响原对象.
# 简单来说: 浅拷贝会创建一个新对象,但只拷贝第一次内容,对于嵌套的对象仍然使用引入.
import copy
a = [1, 2, [3, 4]]
b = copy.copy(a) # 浅拷贝
a[0] = 10
print(b) # 输出: [1, 2, [3, 4]] - b的第一层不受影响
a[2][0] = 30
print(b) # 输出: [1, 2, [30, 4]] - 嵌套列表被修改了
# 底层原理:
# 浅拷贝仅复制顶层容器的结构,不会递归复制子对象.
# 新对象的每个元素是原对象的引入(即指向相同的内存地址).
# 创建拷贝的方法:
# 1、copy.copy()
# 2、列表的切片操作 list[:]
# 3、字典的 dict.copy() 方法
# 4、集合的 set.copy() 方法
# 5、构造函数
# ③ 深拷贝: deepcopy (Deep Copy)
# 深拷贝会创建一个完全独立的新对象, 递归复制所有嵌套对象,确保新对象与原对象及其子对象无任何引用关系.
# 修改原对象的任何层级都不会影响原对象。
# 简单来说:深拷贝会递归地拷贝所有嵌套对象,创建一个完全独立的新对象。
# 底层原理:
# 通过递归遍历原对象的所有层级,逐层复制每个子对象.生成全新的内存地址.
# 对于不可变对象(如 数值类型,字符串等)不会复制, 而是直接引用原值.(因为不可变对象无法修改)
# 对于可变对象(如 列表, 字典, 集合),深拷贝会逐层复制,确保完全独立.
import copy
a = [1, 2, [3, 4]]
b = copy.deepcopy(a) # 深拷贝
a[0] = 10
a[2][0] = 30
print(a) # 输出: [10, 2, [30, 4]]
print(b) # 输出: [1, 2, [3, 4]] - b完全不受影响
# 深拷贝的特点:
# 创建完全独立的对象副本
# 修改原对象不会影响拷贝后的对象
# 对于嵌套结构特别有用
# 性能开销比浅拷贝大
# 总结: 3种拷贝方式的使用场景
# 赋值: 当你确实需要共享同一个对象时
# 浅拷贝: 当对象没有嵌套结构 或 你确定需要共享嵌套对象时
# 深拷贝: 当需要完全独立的副本,特别是对象包含嵌套结构时.
import copy
original = [1, [2, 3], {'a': 4}]
# 赋值
assigned = original
# 浅拷贝
shallow_copied = copy.copy(original)
# 深拷贝
deep_copied = copy.deepcopy(original)
# 修改原始对象
original[0] = 10
original[1][0] = 20
original[2]['a'] = 40
# [10, [20, 3], {'a': 40}]
# [1, [20, 3], {'a': 40}]
# [1, [2, 3], {'a': 4}]
print("赋值后的:", assigned) # 完全跟随变化 [10, [20, 3], {'a': 40}]
print("浅拷贝的:", shallow_copied) # 第一层不变,嵌套对象变化 [1, [20, 3], {'a': 40}]
print("深拷贝的:", deep_copied) # 完全不变 [1, [2, 3], {'a': 4}]
# 注意:
# 元组中如果只包含不可变对象,则深拷贝没有效果(地址值一样)
nums1 = (10, 20, 30, 40, 50)
nums2 = copy.deepcopy(nums1)
print(id(nums1)) # 2538809262784
print(id(nums2)) # 2538809262784
# 包含可变对象(列表),地址值不一样
nums3 = (10, 20, 30, 40, 50, [60, 70])
nums4 = copy.deepcopy(nums3)
print(id(nums3)) # 2919098428352
print(id(nums4)) # 2919098426720
print('------------------9')
# 10. 四种作用域 LEGB
# ① 局部作用域 (Local Scope)
# 定义: 函数或方法内部定义的变量
# 特点: 仅在函数内有效,函数执行结束后销毁.
# ② 嵌套作用域 (Enclosing Scope)
# 定义: 闭包函数中,外层函数(非全局)的变量
# 特点: 通过nonlocal关键字修改
# ③ 全局作用域 (Global Scope)
# 定义: 模块顶层定义的变量.
# 特点: 通过 gloabl 关键字在函数内修改.
# ④ 内置作用域 (Built-in Scope)
# 定义: Python内置函数和异常(如 print / len / ValueError)
# 特点: 无需定义,即可全局(所有.py文件)调用.
# 作用域优先级: ( LEGB 规则)
# Python按 L -> E -> G -> B的顺序查找变量.
# Local(局部) → 2. Enclosing(嵌套) → 3. Global(全局) → 4. Built-in(内置)。
# 变量覆盖:局部变量与全局变量同名时,优先使用局部变量。
# 修改作用域:通过global和nonlocal关键字显式声明。
a = 100
def test(b):
print('我是test函数')
print('test中打印的a是', a) # 100
print('test中收到的参数b是', b) # 66
c = 200
d = 300
print('test中的c和d是: ', c, d) # 200 300
def inner():
a = 888
e = 400
nonlocal c
c = 999
print('inner中的e是', e) # 400
print('inner中打印的c是', c) # 999
print('#############', a) # 100
inner()
print('#############', c) # 999
print('全局打印的a是', a) # 100
test(66)
# 全局打印的a是 100
# 我是test函数
# test中打印的a是 100
# test中收到的参数b是 66
# test中的c和d是: 200 300
# inner中的e是 400
# inner中打印的c是 999
# ############# 100
# ############# 999
print('------------------10')
# 11. 闭包
# 前置知识1
# 每次调用函数时,Python都会为函数创建一个新的局部作用域
# 函数执行完毕后,这个局部作用域会被销毁,其中的局部变量也会随之被释放.
# def outer():
# num = 10
# num += 1
# print(num)
#
# outer() # 11
# outer() # 11
# outer() # 11
# 前置知识2
# 在Python中, [内层函数]可以访问其[外层函数]作用域中的变量
# 访问外层函数变量,无需使用nonlocal 但是修改外层变量时要是有 nonlocal
# def outer():
# num = 10
# def inner():
# nonlocal num
# num = 99
# print(1, num) # 1 99
# inner()
# print(2, num) # 2 99
#
# outer()
# 闭包: 闭包 = 内层函数 + 被内层函数所引用的外层变量
# 闭包 = 嵌套函数 + 引用外部函数变量 + 外部函数返回嵌套函数
# 在一个外部函数里定义一个内部函数
# 内部函数使用了外部函数的变量 / 参数
# 外部函数把内部函数作为返回值返回
# 这个被返回的内部函数 + 它引用的外部变量,就叫闭包
# 闭包产生的条件:
# 要有函数嵌套
# 在 [内层函数] 中,要访问[外层函数] 的变量
# 并且 [外层函数] 要返回 [内层函数] --- 只有返回了内层函数,闭包才能 '活下来'
def outer():
num = 10
def inner():
nonlocal num
num += 1
print(num)
print(inner.__closure__)
return inner
f = outer() # (<cell at 0x00000139F3868520: int object at 0x00007FFB3696E448>,)
f() # 11
f() # 12
f() # 13
f2 = outer() # (<cell at 0x00000139F3869B10: int object at 0x00007FFB3696E448>,)
f2() # 11
f2() # 12
f2() # 13
# 结论:
# outer函数中,被inner所使用到的那些变量,会被封存到 [闭包单元 cell]中.
# 这些 cell 会组成一个 __closure__ 元组,最终放到了 inner 函数身上.
# 打印__closure__元组
print(f.__closure__) # (<cell at 0x00000139F3868520: int object at 0x00007FFB3696E4A8>,)
# 打印__closure__元组中的某一项
print(f.__closure__[0]) # <cell at 0x00000139F3868520: int object at 0x00007FFB3696E4A8>
# 打印__closure__元组中的某一项的具体值
print(f.__closure__[0].cell_contents) # 13
# 注意:
# 调用n次外层函数,就会得到n个不同的闭包,并且这些闭包之前互不影响.
# 内层函数中用到的外层变量是可变函数,多个闭包之间依然互不影响.
def outer():
num = []
def inner(value):
nonlocal num
num.append(value)
print(num)
return inner
f = outer()
f(10) # [11]
f(20) # [11, 22]
f(30) # [11, 22, 33]
f2 = outer()
f2(666) # 66
# 闭包的优点:
# 可以 '记住' 状态: 不用全局变量.也不用写类,就能在多次调用之间保存数据
# 可以做 '配置过的函数' : 先传一部分参数,把环境固定住,得到一个定制版函数.
# 可以实现简单的 '数据隐藏' :外层变量对外不可见,只能通过内层函数访问.
# 是装饰器 (decorator)等高级用法的基础.
def beauty(char, n):
def show_msg(msg):
print(char * n + msg + char * n)
return show_msg
s1 = beauty('*' , 3)
s1('闫闫') # ***闫闫***
s1('陈陈') # ***陈陈***
s2 = beauty('@' , 5)
s2('铮') # @@@@@铮@@@@@
s2('宝') # @@@@@宝@@@@@
# 闭包的缺点:
# 理解成本较高: 对初学者不太友好,滥用会让代码难读
# 如果闭包引用了很大的对象,又长期不释放,可能会增加内存占用
# 很多场景下, 其实用 [ 类 + 实力属性 ]会更清晰,闭包不一定是最优解
class Beauty:
def __init__(self, char, n):
self.char = char
self.n = n
def show(self, msg):
print(self.char * self.n + msg + self.char * self.n)
s2 = Beauty('*', 3)
s2.show('闫闫') # ***闫闫***
s2.show('陈陈') # ***陈陈***
# 闭包 vs 类
# 保存少量状态
# 闭包:推荐,轻量,代码少
# 类:重量级
# 复杂功能
# 闭包:不适合
# 类:适合
# 装饰器
# 闭包:必须用闭包
# 类:无法替代
# 闭包的核心用途:
# 保存函数状态 (计数器, 缓存, 记录历史)
# 装饰器底层实现(Python装饰器本质就是闭包)
# 工厂函数(批量生产功能相似的函数)
# 数据封装(替换简单类,比类更轻量)
# 避坑1
# 循环中创建闭包,变量延迟绑定
def f():
funcs = []
for i in range(3):
def func():
return i
funcs.append(func)
return funcs
f1, f2, f3 = f()
print(f1(), f2(), f3()) # 全部输出 2(不是预期 0,1,2)
# 原因:闭包延迟绑定,循环结束后 i=2,所有函数共用同一个 i
# 解决方法:给内部函数加默认参数(立即绑定)
def f():
funcs = []
for i in range(3):
def func(n=i): # 立即绑定当前 i
return n
funcs.append(func)
return funcs
f1, f2, f3 = f()
print(f1(), f2(), f3()) # 0 1 2
# 避坑2 : 修改外部变量忘记加 nonlocal
# 修改必须加 nonlocal 否则会报错/创建局部变量
print('------------------11')
# 12.装饰器
# 装饰器是一种 [可调用对象](通常是函数).它能接收一个函数作为参数,并且会返回一个新函数.
# 装饰器可以在不修改原函数代码的前提下,增强或改变原函数的功能.
# 12.1 函数装饰器
# 关键点:
# 接收被装饰的函数,同时返回新函数 (wrapper) [原函数---> 装饰器 ---> 新函数 ]
# 装饰器 '吐出来'的是wrapper函数,以后别人调用的也是 wrapper函数
# 为了保证参数的兼容性,wrapper函数要通过 *args 和 ** kwargs接收参数
# wrapper 函数中主要做的是: 调用原函数(被装饰的函数),执行其他逻辑,但是记得将原函数的返回值 return 出去.
# 实际应用:
# 在不改变原函数的前提下,给函数统一加上:日志记录、计时、校验、缓存、性能分析、权限控制
# 日志记录: 装饰器可用于记录函数的调用信息、参数和返回值。
# 性能分析: 可以使用装饰器来测量函数的执行时间。
# 权限控制: 装饰器可用于限制对某些函数的访问权限。
# 缓存: 装饰器可用于实现函数结果的缓存,以提高性能。
def say_hello(func):
def wrapper(*args, **kwargs):
print('hello Python')
return func(*args, **kwargs)
return wrapper
@say_hello
def add(x, y):
res = x + y
print(f'{x}和{y}相加的结果是:{res}')
return res
# 正常调用add函数
# r = add(1, 2)
# print(r) # 3
# 需求: 在不改变add函数的前提下,给add函数增加一些额外的功能,例如: 计算前先打印一句欢迎语
# 实现方案: 使用装饰器
r = add(1, 2)
print(r)
# hello Python
# 1和2相加的结果是:3
# 3
# 进阶1: 带参数的装饰器
# 三层嵌套,外层接收配置,中间层接收函数,内层接收具体参数
def say_hello(msg):
def outer(func):
def wrapper(*args, **kwargs):
print('hello Python')
return func(*args, **kwargs)
return wrapper
return outer
@say_hello('加法')
def add(x, y):
res = x + y
print(f'{x}和{y}相加的结果是:{res}')
return res
@say_hello('减法')
def sub(x, y):
res = x - y
print(f'{x}和{y}相减的结果是:{res}')
return res
r2 = add(3, 4)
print(r2)
# hello Python
# 3和4相加的结果是:7
# 7
r3 = sub(5, 6)
print(r3)
# hello Python
# 5和6相减的结果是:-1
# -1
# 进阶2: 多个装饰器一起使用
def test1(func):
def wrapper(*args, **kwargs):
print('hello test1')
return func(*args, **kwargs)
return wrapper
def test2(func):
def wrapper(*args, **kwargs):
print('hello test2')
return func(*args, **kwargs)
return wrapper
@test1
@test2
def add(x, y):
res = x + y
print(f'{x}和{y}相加的结果是:{res}')
return res
r5 = add(7, 8)
print(r5)
# hello test1
# hello test2
# 7和8相加的结果是:15
# 15
# 12.2 类装饰器
# 包含__call__ 方法发类,就是类装饰器
# 像调用函数一样,去调用类装饰器的实例对象,就会触发__call__ 方法的调用
# __call__ 方法通常接收一个函数作为参数,并且会返回一个新函数
class SayHello:
def __init__(self, msg):
self.msg = msg
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f'hello Python- {self.msg}')
return func(*args, **kwargs)
return wrapper
# 使用@语法糖使用类装饰器
@SayHello('加法')
def add(x, y):
res = x + y
print(f'{x}和{y}相加的结果是:{res}')
return res
r11 = add(12, 13)
print(r11)
# hello Python- 加法
# 12和13相加的结果是:25
# 25
# 多个类装饰器的使用
class Test1:
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f'hello Test1')
return func(*args, **kwargs)
return wrapper
class Test2:
def __call__(self, func):
def wrapper(*args, **kwargs):
print(f'hello Test2')
return func(*args, **kwargs)
return wrapper
@Test1()
@Test2()
def add(x, y):
res = x + y
print(f'{x}和{y}相加的结果是:{res}')
return res
r12 = add(14, 15)
print(r12)
# hello Test1
# hello Test2
# 14和15相加的结果是:29
# 29
print('------------------12')
# 13. 类型注解
# 类型注解就是在代码中注明数据类型的语法
# 目的:
# 提高代码可读性:让他人(以及未来的你)一眼就能看懂代码的意图
# 便于静态检查:在运行代码前,通过工具发现潜在的类型错误
# 增强IDE支持:让代码编辑器提供更准确的自动补全和提示
# 13.1 变量类型注解
# 给变量加上类型说明,可增强代码的可读性,让IDE的提示更友好
num: int = 100
price: float = 12.5
message: str = '陈振'
is_vip: bool = True
result: None = None # 语法上这样写没问题,但这么写没意义
# 注意: 可以先写变量的类型注解,以后再赋值
school: str
print('--')
school = 'fsf'
# hobby是列表,并且列表中的所有元素必须是 str类型
hobby1: list[str] = ['喝酒', '抽烟', '烫头']
# hobby是列表,并且列表中的所有元素必须是 str 或 int类型
hobby2: list[str | int] = ['喝酒', '抽烟', '烫头', 10]
# 上面这行代码的旧写法如下:
from typing import Union
hobby3: list[Union[str, int]] = ['喝酒', '抽烟', '烫头', 10]
# cits是集合,并且集合中所有元素必须是 str 类型
citys1: set[str] = {'北京', '上海', '深圳'}
# cits是集合,并且集合中所有元素必须是 str 或 float 或 bool 类型
citys2: set[str | float | bool] = {'北京', '上海', '深圳'}
# persons 是字典.键是str类型, 值是 int类型
persons1: dict[str, int] = {'张三': 19, '李四': 20, '王五': 18}
# persons 是字典.键是str 或 int类型, 值是 int类型
persons2: dict[str | int, int] = {'张三': 19, '李四': 20, '王五': 18}
# 注意: 元组的类型声明有点特殊
# scores 是元组, 并且元组中仅包含1个int类型的元素
scores: tuple[int] = (60,)
# scores 是元组, 并且元组中仅包含3个int类型的元素
scores: tuple[int, int, int] = (60, 70, 80)
# scores 是元组, 并且元组中仅包含任意个数的元素,但每个元素的类型必须是int
scores: tuple[int, ...] = (60, 70, 80, 90)
# scores 是元组, 并且元组中仅包含任意个数的元素,但每个元素的类型必须是int 或 str
scores: tuple[int | str, ...] = (60, 70, 80, 90, 'sb')
# Python会根据初始赋值推导变量的类型.
# 对于普通变量: 后续如果改变类型,不会警告
# 对于容器变量: 要求内部元素类型必须与推导出来的一致,否则就会警告.
x = 100
x = 'hello'
y = [10, 20, 30]
y.append('hah') # 有警告
# 13.2 函数类型注解
# 给函数的[参数]和[返回值]添加类型说明
# 语法格式: 函数名(参数1:类型,参数2:类型) -> 返回值类型:
# 示例1:设置参数类型注解,设置返回值类型注解
def add(x: int, y: int) -> int:
return x + y
# 示例2: 参数有默认值(Python可以推导出参数的类型),设置返回值类型
def add2(x=1, y=2) -> int:
return x + y
# 示例3:设置多个返回值的类型注解
def show_nums_info(nums: list[int]) -> tuple[int, int, float]:
max_num = max(nums)
min_num = min(nums)
result = max_num - min_num
return max_num, min_num, result
# 示例4: 设置 *args 的类型注解,要求 args 中的每个蟾酥都必须是 int类型
def add3(*args: int) -> int:
return sum(args)
# 示例5: 设置 **kwargs 的类型注解,要求kwargs中的每组参数的值,必须是 str 或 int类型
def show_info(**kwargs: str | int):
print(kwargs)
# 获取函数的注解信息
print(show_info.__annotations__) # {'kwargs': str | int}
7.错误与异常
目录:
1.错误与异常
1.1 介绍
1.2 一些开发中常见的异常
1.3 Python中异常层次结构
2.异常处理
3.手动抛出异常
4.异常传递机制
5.自定义异常
python
# 目录:
# 1.错误与异常
# 1.1 介绍
# 1.2 一些开发中常见的异常
# 1.3 Python中异常层次结构
# 2.异常处理
# 3.手动抛出异常
# 4.异常传递机制
# 5.自定义异常
import traceback
# 1.错误与异常
# 1.1 介绍
# 错误;
# 代码本身有语法错误,解释器无法执行代码. -无法通过异常处理机制解决.
# 异常:
# 代码在语法上没有问题,但执行过程中出现了问题. - 可以通过异常处理机制解决
# 1.2 一些开发中常见的异常:
# ① ZeroDivisionError : 当除数为0时触发
# num1 = 100
# num2 = 0
# result = num1 / num2
# ② TypeError : 当操作的数据类型不正确或不兼容时触发.
# result = '10' + 5
# ③ AttributeError : 当对象没有指定的属性或方法时触发.
# 演示1:
# class Person:
# def __init__(self, name, age):
# self.name = name
# self.age = age
# p1 = Person('张三', 18)
# print(p1.gender)
# 演示2:
# nums = [10, 20, 30]
# nums.add(100)
# ④ IndexError : 当索引超出范围而(索引越界)时触发.
# nums = [10, 20, 30, 40]
# print(nums[4])
# ⑤ NameError : 当使用了不存在的变量时触发
# print(school)
# ⑥ KeyError : 当访问了字典中不存在的 key 时触发.
# persons = {'name': 'zs', 'age': 18}
# print(persons['gender'])
# ⑦ ValueError : 当值不合法,但类型正确时触发.
# int('hello')
# 1.3 Python中异常层次结构:
# BaseException
# ├── BaseExceptionGroup
# ├── GeneratorExit
# ├── KeyboardInterrupt
# ├── SystemExit
# └── Exception ---> 开发中常见的异常,基本都属于Exception
# ├── ArithmeticError
# │ ├── FloatingPointError
# │ ├── OverflowError
# │ └── ZeroDivisionError
# ├── AssertionError
# ├── AttributeError
# ├── BufferError
# ├── EOFError
# ├── ExceptionGroup [BaseExceptionGroup]
# ├── ImportError
# │ └── ModuleNotFoundError
# ├── LookupError
# │ ├── IndexError
# │ └── KeyError
# ├── MemoryError
# ├── NameError
# │ └── UnboundLocalError
# ├── OSError
# │ ├── BlockingIOError
# │ ├── ChildProcessError
# │ ├── ConnectionError
# │ │ ├── BrokenPipeError
# │ │ ├── ConnectionAbortedError
# │ │ ├── ConnectionRefusedError
# │ │ └── ConnectionResetError
# │ ├── FileExistsError
# │ ├── FileNotFoundError
# │ ├── InterruptedError
# │ ├── IsADirectoryError
# │ ├── NotADirectoryError
# │ ├── PermissionError
# │ ├── ProcessLookupError
# │ └── TimeoutError
# ├── ReferenceError
# ├── RuntimeError
# │ ├── NotImplementedError
# │ ├── PythonFinalizationError
# │ └── RecursionError
# ├── StopAsyncIteration
# ├── StopIteration
# ├── SyntaxError
# │ └── IndentationError
# │ └── TabError
# ├── SystemError
# ├── TypeError
# ├── ValueError
# │ └── UnicodeError
# │ ├── UnicodeDecodeError
# │ ├── UnicodeEncodeError
# │ └── UnicodeTranslateError
# └── Warning
# ├── BytesWarning
# ├── DeprecationWarning
# ├── EncodingWarning
# ├── FutureWarning
# ├── ImportWarning
# ├── PendingDeprecationWarning
# ├── ResourceWarning
# ├── RuntimeWarning
# ├── SyntaxWarning
# ├── UnicodeWarning
# └── UserWarning
# 2.异常处理
# 2.1 为什么要进行异常处理?
# ① 程序运行过程中出现的异常,如果得不到处理,那程序就会立即崩溃,导致后续代码无法执行
# ② 异常处理不是让异常消失,而是将异常捕获到,随后根据异常的具体情况,来执行指定的逻辑
# print('欢迎来到本程序')
# a = int(input('请输入第一个数:'))
# b = int(input('请输入第二个数:'))
# result = a / b
# print(f'{a}除以{b}的结果是:{result}')
# print('******我是后续操作1*******')
# print('******我是后续操作2*******')
# 2.2 异常处理(初级)
# ① 将可能出现异常的代码放在 try中,出现异常后的处理代码写在except中
# ② 如果 try 中的代码出现异常,那try中的后续代码将不会执行,并自动跳转到 except中处理异常
# ③ 如果try中的代码没有异常,那except中的代码就不会执行
# ④ 无论是否发生异常,try-except后面的代码都会继续执行.
# print('欢迎来到本程序')
# try:
# a = int(input('请输入第一个数:'))
# b = int(input('请输入第二个数:'))
# result = a / b
# print(f'{a}除以{b}的结果是:{result}')
# except:
# print('抱歉,程序出现了异常!')
# print('******我是后续操作1*******')
# print('******我是后续操作2*******')
# 2.3 异常处理(捕获指定的类型的异常)
# print('欢迎来到本程序')
# try:
# a = int(input('请输入第一个数:'))
# b = int(input('请输入第二个数:'))
# result = a / b
# print(f'{a}除以{b}的结果是:{result}')
# except ZeroDivisionError:
# print('程序异常,0不能作为除数!')
# except ValueError:
# print('程序异常,你输入的必须是数字!')
# print('******我是后续操作1*******')
# print('******我是后续操作2*******')
# 2.4 验证一下异常类之间的继承关系
print(issubclass(ZeroDivisionError, ArithmeticError)) # True
print(issubclass(ZeroDivisionError, Exception)) # True
print(issubclass(ValueError, Exception)) # True
print(issubclass(KeyboardInterrupt, Exception)) # False
print(issubclass(KeyboardInterrupt, BaseException)) # True
# 2.5 多个except从上往下匹配,匹配成功后不再往下匹配
# print('欢迎来到本程序')
# try:
# a = int(input('请输入第一个数:'))
# b = int(input('请输入第二个数:'))
# print(x)
# result = a / b
# print(f'{a}除以{b}的结果是:{result}')
# except ZeroDivisionError:
# print('程序异常,0不能作为除数!')
# except ValueError:
# print('程序异常,你输入的必须是数字!')
# except Exception:
# print('程序异常!')
# print('******我是后续操作1*******')
# print('******我是后续操作2*******')
# 2.6 获取异常的具体信息
# print('欢迎来到本程序')
# try:
# a = int(input('请输入第一个数:'))
# b = int(input('请输入第二个数:'))
# print(x)
# result = a / b
# print(f'{a}除以{b}的结果是:{result}')
# except ZeroDivisionError:
# print('程序异常,0不能作为除数!')
# except ValueError:
# print('程序异常,你输入的必须是数字!')
# except Exception as e:
# print(f'程序异常, 异常信息: {e}')
# print(f'程序异常, 异常信息: {type(e)}')
# print(f'程序异常, 异常信息: {e.args}')
# print(f'程序异常, 异常信息: {e.__traceback__.tb_frame.f_code.co_filename}')
# print(f'程序异常, 异常信息,具体行数: {e.__traceback__.tb_lineno}')
# # 后续使用 trackback 打印异常信息(回溯异常)
# import traceback
# print(traceback.format_exc())
# print('******我是后续操作1*******')
# print('******我是后续操作2*******')
# 2.7 一个except, 也可以捕获不同的异常
# print('欢迎来到本程序')
# try:
# a = int(input('请输入第一个数:'))
# b = int(input('请输入第二个数:'))
# # print(x)
# result = a / b
# print(f'{a}除以{b}的结果是:{result}')
# except(ZeroDivisionError, ValueError, Exception) as e:
# import traceback
#
# if isinstance(e, ZeroDivisionError):
# print('程序异常,0不能作为除数!')
# print(traceback.format_exc())
# elif isinstance(e, ZeroDivisionError):
# print('程序异常,你输入的必须是数字!')
# print(traceback.format_exc())
# else:
# print(f'程序异常, 异常信息: {e}')
# print(traceback.format_exc())
# print('******我是后续操作1*******')
# print('******我是后续操作2*******')
# 2.8 异常处理的完整写法:
# try: 尝试去做可能会出现的异常的事情
# except: 出现异常时的处理(出现异常时如何补救)
# else: 如果一切顺利(没有出现异常) 要做的事
# finally: 无论有没有异常,都要做的事
# print('欢迎来到本程序')
# try:
# a = int(input('请输入第一个数:'))
# b = int(input('请输入第二个数:'))
# # print(x)
# result = a / b
# print(f'{a}除以{b}的结果是:{result}')
# except(ZeroDivisionError, ValueError, Exception) as e:
# import traceback
# if isinstance(e, ZeroDivisionError):
# print('程序异常,0不能作为除数!')
# print(traceback.format_exc())
# elif isinstance(e, ZeroDivisionError):
# print('程序异常,你输入的必须是数字!')
# print(traceback.format_exc())
# else:
# print(f'程序异常, 异常信息: {e}')
# print(traceback.format_exc())
# else:
# print('every thing is ok')
# finally:
# print("no matter what, it's over!")
# print('******我是后续操作1*******')
# print('******我是后续操作2*******')
print('------------------2')
# 3.手动抛出异常
# 当程序遇到不符合预期情况时,可以使用 raise 语句手动触发(抛出)异常.
print('欢迎使用年龄管理系统')
try:
age = int(input('请输入你的年龄:'))
if 18 <= age <= 120:
print('成年')
elif 0 <= age < 18:
print('未成年')
else:
# print('你输入的年龄有误!(年龄应该是在 0-120的整数)')
raise ValueError('年龄应该是在 0-120的整数')
except Exception as e:
print(f'程序异常:{e}')
print(traceback.format_exc())
# raise NameError('名称有误')
# raise KeyboardInterrupt('键盘打扰')
# 4.异常传递机制
# 如果异常没有被当前代码块捕获处理,那该异常就会沿着调用链,逐层传递给其调用者.
# 如果所有调用者,都没有捕获该异常,那最终程序将因[未处理异常]而意外终止.
# def test1():
# print('test1')
# result = '100' + 100
# print('test11')
# def test2():
# print('test2')
# test1()
# print('test22')
# def test3():
# print('test3')
# test2()
# print('test33')
#
# try:
# test3()
# except Exception as e:
# print('程序异常:', e)
# 5.自定义异常
# 由开发人员自己定义的一个异常类,用来表示代码中 '更具体,更有业务含义'的异常.
# 具体规则: 定义一个类(类名通常以 Error 结尾)继承 Exception 类或它的子类.
class SchoolNameError(Exception):
def __init__(self, msg):
super().__init__('[校名异常]' + msg)
def check_school_name(name):
if len(name) > 10:
raise SchoolNameError('学校名字过长!')
else:
print('学校名字合法!')
check_school_name('阜阳师范大学')
check_school_name('阜阳师范大学1111111')