commit 0abf1ad3c4ab8cb1076c2121a7fb86c226a82b10 Author: heyong.fu Date: Wed May 6 11:21:42 2026 +0800 feat: python diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..688b598 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1075389 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv + +# IDE +.idea/ +.vscode/ +*.swp + +# OS files +.DS_Store diff --git a/13-17/01pint.py b/13-17/01pint.py new file mode 100644 index 0000000..3763641 --- /dev/null +++ b/13-17/01pint.py @@ -0,0 +1,133 @@ +# 基础打印 +print("Hello Word") +print(100) +print(3.14) +print(True) + + +# 多个值 +# 会自动用空格分开 +name = "小明" +age = 18 +print(name, age) # 小明 18 + +# print 参数 +# 1. sep 分隔符 +# sep 参数可以将多个输出对象用指定分隔符进行分割,默认情况下,print使用的是空格 +print("小明", 18, sep=",") # 小明,18 +print("年", "月", "日", sep="-") # 年-月-日 +print("Hello", "World", sep="") # HelloWorld 无分割 +print("Python", "Java", "javascript", sep="|") # Python|Java|javascript + +# 2.end 结束符 +# 用于指定输出结尾的字符,默认值是换行(\n) +print("第一行") +print("第二行") +print("Hello", end=" ") +print("World", end="!") # Hello World! +print() +print("加载中", end="") +print("....", end="") # 加载中.... + +print() +# 组合使用sep和end +print("苹果", "香蕉", "西瓜", sep=", ", end="都是水果") # 苹果, 香蕉, 西瓜都是水果 + +print() +print("姓名", "年龄", "城市", sep="|", end="\n----\n") +print("张三", 25, "北京", sep="|") +# 姓名|年龄|城市 +# ---- +# 张三|25|北京 + +# 3. file 输出到文件 +# file 参数用于指定输出文件目标,默认是sys.stdout(标准输出,屏幕)。可以将输出重定向到文件或者标准错误流。 +with open("optput.txt", "w", encoding="utf-8") as f: + print("这是写入的文件的内容", file=f) + print("这是第二行内容", file=f) + +# 输出到标准错误 +import sys + +print("这是一个错误信息", file=sys.stderr) + +# 输出到多个目标 +with open("log.txt", "w", encoding="utf-8") as fs: + msg = "重要信息" + print(msg) # 输出到屏幕 + print(msg, file=fs) # 输出到log.txt + + +# 4 flush 强制舒心缓冲区 +# flush 参数用于控制输出缓冲区的刷新行为。默认是False,输出内容先存储在缓冲区中,系统决定合适显示。设置为True时,内容会立即展示 +import time + +# print("开始", end="") +# time.sleep(2) +# print("结束") + +# 使用flush +# print("开始", end="", flush=True) +# time.sleep(2) +# print("结束") + +# print("下载中", end="", flush=True) +# for i in range(5): +# time.sleep(0.5) +# print(".", end="", flush=True) +# print("完成") + + +# 格式化输出 +# 1. f{} 在字符串前加上f,通过{}包裹变量或者表达式 +name = "Bob" +age = 20 +sorce = 98.88 +print(f"姓名{name},年龄{20},成绩{100}") + +# 表达式计算 +print(f"年龄{age+1}") +print(f"分数翻倍{sorce*2}") + +# 数字格式换(会四舍五入) +print(f"分数保留1位小数{sorce:.1f}") # 98.8 +print(f"分数保留2位小数{sorce:.2f}") # 98.82 + +# 对齐 +print(f"{name:>10}") # 右对齐,宽度是10 Bob +print(f"{name:<10}") # 左对齐,宽度是10 Bob +print(f"{name:^10}") # 居中对齐 + +# 进制转换 +num = 255 +print( + f"十进制{num},十六进制{num:x},二进制{num:b}" +) # 十进制255,十六进制ff,二进制11111111 + +# 2. format() 方法 +# format方法是python3中常用的字符串格式化的方式,兼容性比较好 +name = "Bob" +age = 30 +sorce = 90.52 +# 按顺序填充 +print("姓名{},年龄{},成绩{}".format(name, age, sorce)) +# 按指定索引填充 +print("姓名{2},年龄{0},成绩{1}".format(age, sorce, name)) +# 使用关键字填充 +print("姓名{n},年龄{a},成绩{s}".format(n=name, a=age, s=sorce)) +# 数字格式化 +print("保留一位小数{:.1f}".format(sorce)) +# 对齐和填充 +print("{:<10}{:>10}".format(name, age)) + +# 3. % 传统格式化 +# % 格式化是Pyhon早期格式化字符串的方式,目前仍在使用,但不推荐 +name = "Bob" +age = 30 +sorce = 90.52 +print("姓名:%s,年龄:%d,分数:%.2f" % (name, age, sorce)) +# %s 字符串 +# %d 整数 +# %f 浮点数 +# %.2f 保留两位小数 +print(0b1010 + 0o12 + 0xA) diff --git a/13-17/02int.py b/13-17/02int.py new file mode 100644 index 0000000..454c311 --- /dev/null +++ b/13-17/02int.py @@ -0,0 +1,109 @@ +# 整型 +# 整型int 包括正整数,负整数,和零 +# 基本整型定义 +positive = 42 +negative = -15 +zero = 0 + +print(f"positive{positive},类型{type(positive)}") # positive42,类型 +print(f"negative{negative},类型{type(negative)}") # negative-15,类型 +print(f"zero{zero},类型{type(zero)}") # zero0,类型 + + +# 支持不同进制的整型表示 +# 十进制 (默认) +decimal = 10 +print(f"十进制 10: {decimal}") + +# 二进制 (以 0b 或 0B 开头) +binary = 0b1010 # 二进制 1010 = 十进制 10 +print(f"二进制 0b1010: {binary}") + +# 八进制 (以 0o 或 0O 开头) +octal = 0o12 # 八进制 12 = 十进制 10 +print(f"八进制 0o12: {octal}") + +# 十六进制 (以 0x 或 0X 开头) +hexadecimal = 0xA # 十六进制 A = 十进制 10 +print(f"十六进制 0xA: {hexadecimal}") + +# 使用下划线提高可读性 (Python 3.6+) +large_number = 1_000_000 +print(f"大数字: {large_number}") + +credit_card = 1234_5678_9012_3456 +print(f"信用卡号: {credit_card}") + +bytes_value = 0b1100_1010_1111_0101 +print(f"字节值: {bytes_value}") + +# 整型转换 +# int() +print(f"int(3.14) = {int(3.14)}") # 3 +print(f"int(-2.99) = {int(-2.99)}") # -2 +print(f"int('100') = {int('100')}") # 100 +print(f"int('1010', 2) = {int('1010', 2)}") # 二进制字符串转十进制 +print(f"int('FF', 16) = {int('FF', 16)}") # 十六进制字符串转十进制 +print(f"int(True)={int(True)}") # 1 +print(f"int(False)={int(False)}") # 0 + + +# 进制转换函数 +number = 10 +print(f"\n数字 {number} 的不同进制表示:") +print(f"二进制: {bin(number)}") # 0b1010 +print(f"八进制: {oct(number)}") # 0o12 +print(f"十六进制: {hex(number)}") # 0xa + +# 基本运算符 +a, b = 10, 3 + +print("基本算术运算:") +print(f"{a} + {b} = {a + b}") # 加法: 13 +print(f"{a} - {b} = {a - b}") # 减法: 7 +print(f"{a} * {b} = {a * b}") # 乘法: 30 +print(f"{a} / {b} = {a / b}") # 除法: 3.333... (返回浮点数) +print(f"{a} // {b} = {a // b}") # 整除: 3 +print(f"{a} % {b} = {a % b}") # 取余: 1 +print(f"{a} ** {b} = {a ** b}") # 幂运算: 1000 +print(f"-{a} = {-a}") # 取负: -10 +print(f"+{a} = {+a}") # 取正: 10 + +a, b = 10, 5 + +print("比较运算:") +print(f"{a} == {b}: {a == b}") # 等于: False +print(f"{a} != {b}: {a != b}") # 不等于: True +print(f"{a} > {b}: {a > b}") # 大于: True +print(f"{a} < {b}: {a < b}") # 小于: False +print(f"{a} >= {b}: {a >= b}") # 大于等于: True +print(f"{a} <= {b}: {a <= b}") # 小于等于: False + +# 链式比较 +c = 7 +print(f"\n链式比较:") +print(f"{b} < {c} < {a}: {b < c < a}") # True +print(f"{a} > {c} > {b}: {a > c > b}") # True + + +import math + +numbers = [-5, 0, 5, 10, 15] + +print("内置数学函数:") +for num in numbers: + print(f"abs({num}) = {abs(num)}") # 绝对值 + +print(f"\n最大值: {max(1, 5, 2, 8, 3)}") # 8 +print(f"最小值: {min(1, 5, 2, 8, 3)}") # 1 +print(f"求和: {sum([1, 2, 3, 4, 5])}") # 15 + +# 更多数学函数 +print(f"\n高级数学函数:") +print(f"2的3次方: {pow(2, 3)}") # 8 +print(f"四舍五入: {round(3.14159, 2)}") # 3.14 +print(f"向上取整: {math.ceil(3.14)}") # 4 +print(f"向下取整: {math.floor(3.14)}") # 3 + +n = 3 +print(int(n**0.5)) diff --git a/13-17/03str.py b/13-17/03str.py new file mode 100644 index 0000000..0993fab --- /dev/null +++ b/13-17/03str.py @@ -0,0 +1,248 @@ +# 字符串 +str1 = "字符串" +print(str1, type(str1)) # 字符串 + +# 1.字符串转义字符 +# \n 换行 +# \t 制表符(Tab) +# \\ 标识反斜杠自身 +# \' 单引号 +# \" 双引 +# uXXXX 标识Unicode字符 +# 如果不需要将反斜杠作为转义符使用,可以在字符前面加r,表示原始字符串,反斜杠不会被转移 + +str2 = "换\n行" +print(str2) +str3 = "制表\t符" +print(str3) # 制表 符 +str4 = "反斜杠\\自身" +print(str4) # 反斜杠\自身 +str5 = '单引"号' +print(str5) # 双引号 + +str6 = r"原始字符串\n不会被转义" +print(str6) # 原始字符串\n不会被转义 + +# 2.字符串索引和切片 +# 字符串中的每个字符都可以通过索引(下标)来访问。索引从0开始,也支持负数索引(-1表示最后一个字符,-2表示倒数第二个,以此类推)。 + +text = "Hello Python" +print("索引操作:") +print(f"字符串: '{text}'") +print(f"字符串长度{len(text)}") # 字符串长度12 +print(f"正索引-text[0]:{text[0]}") # H +print(f"正索引-text[6]:{text[6]}") # P +print(f"负索引-text[-1]:{text[-1]}") # n +print(f"负索引-text[-6]:{text[-6]}") # P + +# 切片(slice)可以用来获取字符串中的一部分,语法为 `str[start:end:step]`,其中: +# - `start`:起始索引(包含该位置,默认为0) +# - `end`:结束索引(不包含该位置,默认为字符串长度) +# - `step`:步长(默认为1,可以为负数实现反向切片) +text = "Hello Python Programming" +print(f"text[0:5]:{text[0:6]}") # Hello +print(f"text[6:12]: '{text[6:12]}'") # Python +print(f"text[:5]: '{text[:5]}'") # Hello (从开始到索引5) +print(f"text[13:]: '{text[13:]}'") # Programming (从索引13到结束) +print(f"text[-11:]: '{text[-11:]}'") # Programming (从倒数第11个到结束) + +# 切片步长 +print(f"text[::2]:{text[::2]}") # HloPto rgamn +print(f"text[1::2]: '{text[1::2]}'") # el yhnPormig (从索引1开始,步长为2) +print(f"text[::-1]: '{text[::-1]}'") # gnimmargorP nohtyP olleH (反转) + +# 字符串操作方法 +# 大小写转换 +# upper()全部转大写 +# lower() 全部转小写 +# capitalize()首字母大写,其余小写 +# title()每个单词首字母大写 +# swapcase()大小写互换 + +text = "hello World of Python" +print(f"转大写{text.upper()}") # WORLD OF PYTHON +print(f"转小写{text.lower()}") # world of python +print(f"首字母大写{text.capitalize()}") # Hello world of python +print(f"每个单词首字母大写{text.title()}") # Hello World Of Python +print(f"大小写互换{text.swapcase()}") # HELLO wORLD OF pYTHON + +# 查找和替换 +# find(sub) 查找子串,返回索引,找不到返回-1 +# rfind(sub) 从右侧查找 +# index(sub) 找到子串,找不到抛出异常 +# count(sub) 统计子串出现次数 +# replace(old,new,count) 替换子串 +text = "Hello World, Welcome to Python World" + +print(f"查找Welcome出现的位置{text.find('Welcome')}") # 13 +print(f"查找不存在的{text.find('java')}") # -1 +print(f"从右侧查找{text.rfind('Python')}") # 24 +print(f"从索引查找{text.index('Python')}") # 24 +print(f"出现次数{text.count('Python')}") # 1 +print(f"替换{text.replace('Python','Java')}") # Hello World, Welcome to Java World + +# 字符串检查 +# isalpha():是否全为字母 +# isdigit():是否全为数字 +# isalnum():是否全为字母或数字 +# isspace():是否全为空白字符(如空格、制表符等) +# istitle():是否为标题格式(每个单词首字母大写) +# isupper():是否全为大写字母 +# islower():是否全为小写字母 +# startswith(): 是否以指定子串开头 +# endswith(): 是否以指定子串结尾 + + +def string_checks(): + test_cases = [ + "Hello123", # 字母数字 + "12345", # 纯数字 + "Hello", # 纯字母 + " ", # 纯空格 + "HELLO", # 全大写 + "hello", # 全小写 + "Hello World", # 包含空格 + "", # 空字符串 + ] + print("字符串检查") + for s in test_cases: + print( + f"{s:12}: 字母={s.isalpha():5} 数字={s.isdigit():5} 数字字母={s.isalnum():5} 空格={s.isspace():5} 标题={s.istitle():5}" + ) + + +# string_checks() + +# 开头结尾检查 +filename = "document.pdf" +url = "https://www.example.com" +print(f"\n文件{filename}是PDF嘛?{filename.endswith('pdf')}") +print(f"URL'{url}' 以https开头吗? {url.startswith('https')}") + + +# 去除空格和填充 +# 去除空白字符和字符串填充方法用于格式化字符串内容。 + +# strip():去除字符串两端的空白字符(包括空格、制表符、换行等) +# lstrip():去除左侧空白 +# rstrip():去除右侧空白- +# strip([chars]) 也可以去除指定字符(如'*'、'0'等)- +# center(width, fillchar):内容居中,两侧用fillchar填充 +# ljust(width, fillchar):内容左对齐,右侧用fillchar填充 +# rjust(width, fillchar):内容右对齐,左侧用fillchar填充 +# zfill(width):左侧用0填充,常用于数字字符串 + +text = " Hello World " +print(f"原始: |{text}|") +# 去除字符串两边空格 +print(f"去除字符串两边空格|{text.strip()}|") +# 去除左边空格 +print(f"去除字符串左侧空格|{text.lstrip()}|") +# 去除右边有空格 +print(f"去除字符串右侧空格|{text.rstrip()}|") + +# 包含特定字符的字符串 +text2 = "***Hello World***" +print(f"去除指定字符|{text2.strip("*")}|") + +text3 = "Hello" +# 将字符串居中填充到20个字符宽度并输出 +print(f"居中: |{text3.center(20)}|") +# 将字符串左对齐填充到20个字符宽度并输出 +print(f"左对齐: |{text3.ljust(20)}|") +# 将字符串右对齐填充到20个字符宽度并输出 +print(f"右对齐: |{text3.rjust(20)}|") +# 使用0在左侧填充字符串到10个字符宽度 +print(f"右对齐: |{text3.zfill(10)}|") # 00000Hello + + +# 分割和连接 +# split(sep=None, maxsplit=-1):将字符串按指定分隔符分割成列表,sep为分隔符,maxsplit为分割次数,默认全部分割。 +# rsplit(sep=None, maxsplit=-1):从右侧开始分割,其他用法同split。 +# splitlines(keepends=False):按行分割字符串,返回每一行组成的列表,keepends为True时保留换行符。 +# join(iterable):用指定字符串连接可迭代对象中的元素,生成一个新的字符串。 + +csv_data = "apple,banana,orange,grape" +sentence = "Hello World of Python" +lines = "第一行\n第二行\n第三行" +print(f"csv分割{csv_data.split(',')}") # ['apple', 'banana', 'orange', 'grape'] +print(f"句子分割{sentence.split()}") # ['Hello', 'World', 'of', 'Python'] +print(f"限制分割{sentence.split(' ',2)}") # ['Hello', 'World', 'of Python'] +print(f"按行分割{lines.splitlines()}") # ['第一行', '第二行', '第三行'] + +# 字符串连接 +fruits = ["apple", "banana", "orange"] +print(f"字符串连接{','.join(fruits)}") # apple,banana,orange +print(f"字符串连接{'|'.join(fruits)}") # apple|banana|orange + + +# 字符串格式化 + +# f-string +# 语法:在字符串前加f,花括号{}中放变量或表达式。 +# 例:f"姓名: {name}, 年龄: {age}" +# 优点:简洁、支持表达式、易读。 +name = "Alice" +age = 25 +salary = 5000.50 + +print("f-string格式化:") +print(f"姓名: {name}, 年龄: {age}") +print(f"薪资: ${salary:.2f}") +print(f"明年年龄: {age + 1}") +print(f"名字大写: {name.upper()}") + +# 表达式和函数调用 +items = ["apple", "banana", "orange"] +print(f"物品数量: {len(items)}") +print(f"第二个物品: {items[1]}") + +# 格式化对齐 +number = 42 +print(f"右对齐: |{number:>10}|") +print(f"左对齐: |{number:<10}|") +print(f"居中对齐: |{number:^10}|") +print(f"零填充: |{number:010}|") + +# format() 方法 +# 语法:字符串中用{}占位,调用format()传入对应的值。 +# 例:"{} is {} years old".format(name, age) +# 支持位置参数、关键字参数、格式控制。 +# format() 方法 +name = "Bob" +age = 30 + +print("format() 方法:") +print("{} is {} years old".format(name, age)) +print("{0} is {1} years old. Hello {0}!".format(name, age)) +print("{name} is {age} years old".format(name=name, age=age)) + +# 数字格式化 +pi = 3.14159 +print("PI = {:.2f}".format(pi)) +print("二进制: {:b}".format(10)) +print("十六进制: {:x}".format(255)) + + +# % 操作符 +# 语法:字符串中用%占位符,后面用%传入元组或字典。 +# 例:"%s is %d years old" % (name, age) +# 占位符有%s(字符串)、%d(整数)、%f(浮点数)等。 +# % 操作符 (传统方法) +name = "Charlie" +age = 35 + +print("% 格式化:") +print("%s is %d years old" % (name, age)) +print("PI = %.3f" % 3.14159) + + +# 字符串不可变 +# 字符串在Python中是不可变对象(immutable),这意味着一旦创建,字符串的内容就不能被直接修改。所有对字符串的操作(如拼接、替换、大小写转换等)都会返回一个新的字符串对象,原有字符串保持不变。 + +# 这种不可变性带来如下特点和好处: + +# 安全性:字符串作为键(key)用于字典等哈希结构时,内容不会被意外更改,保证哈希值稳定。 +# 多线程安全:多个线程可以安全地共享字符串对象,无需担心内容被修改。 +# 高效缓存:Python可以对相同内容的字符串进行内部缓存和重用,提升性能。 +# 注意:虽然不能直接修改字符串的某个字符,但可以通过切片、拼接等方式生成新的字符串。 diff --git a/13-17/04bool.py b/13-17/04bool.py new file mode 100644 index 0000000..4cecbe6 --- /dev/null +++ b/13-17/04bool.py @@ -0,0 +1,267 @@ +# 布尔类型的基本概念 +# 布尔类型只有两个值:True 和 False,用于表示真和假。 +is_sunny = True +is_raining = False +print(f"is_sunny:{is_sunny},类型:{type(is_sunny)}") # is_sunny:True,类型: +print( + f"is_raining:{is_raining},类型:{type(is_raining)}" +) # is_raining:False,类型: + +# True 和1 是相等 +print(f"True==1:{True==1}") # True==1:True +# False 和0 是相等 +print(f"False==0:{False==0}") # False==0:True +# True和True的相加结果 +print(f"True+True:{True + True}") # True+True:2 +# True * 10 +print(f"True*10:{True *10}") # True*10:10 +# # False * 10 +print(f"False*10:{False *10}") # False*10:0 + +# 布尔运算 +# 逻辑运算符用于对布尔值进行逻辑运算,主要要三种 +# and(与) 只有两个操作数都为 True 时,结果才为 True,否则为 False。 +# or(或) 只要有一个操作数为 True,结果就为 True,只有两个都为 False 时,结果才为 False。 +# not(非) 对单个布尔值取反,True 变为 False,False 变为 True。 + +# 逻辑运算 +a, b = True, False + +print("逻辑运算:") +print(f"{a} and {b} = {a and b}") # False +print(f"{a} or {b} = {a or b}") # True +print(f"not {a} = {not a}") # False +print(f"not {b} = {not b}") # True + +# 真值表 +print("\n真值表:") +print("AND运算:") +print(f"True and True = {True and True}") # True +print(f"True and False = {True and False}") # False +print(f"False and True = {False and True}") # False +print(f"False and False = {False and False}") # False + +print("\nOR运算:") +print(f"True or True = {True or True}") # True +print(f"True or False = {True or False}") # True +print(f"False or True = {False or True}") # True +print(f"False or False = {False or False}") # False + +print("\nNOT运算:") +print(f"not True = {not True}") # False +print(f"not False = {not False}") # True + +# 逻辑运算符的短路特性 +# 逻辑运算符在运算时具有“短路”特性,也叫“惰性求值”。 + + +# 对于 and 运算符,如果第一个操作数为 False,就不会再计算第二个操作数,结果直接为 False。 +# 对于 or 运算符,如果第一个操作数为 True,就不会再计算第二个操作数,结果直接为 True。 +def expensive_operation(): + print("执行了耗时操作") + return True + + +# and +result1 = False and expensive_operation() # 不执行 +print(result1) # False + +result2 = True and expensive_operation() # 执行 +print(result2) # True + +# or +result3 = True or expensive_operation() # 不执行 +print(result3) # True + +result4 = False or expensive_operation() # 执行 +print(result4) # True + + +# 比较运算符 +# 比较运算符 +x, y = 10, 5 + +print("比较运算:") +print(f"{x} == {y}: {x == y}") # 等于: False +print(f"{x} != {y}: {x != y}") # 不等于: True +print(f"{x} > {y}: {x > y}") # 大于: True +print(f"{x} < {y}: {x < y}") # 小于: False +print(f"{x} >= {y}: {x >= y}") # 大于等于: True +print(f"{x} <= {y}: {x <= y}") # 小于等于: False + +# 字符串比较 +print(f"\n字符串比较:") +print(f"'apple' == 'apple': {'apple' == 'apple'}") # True +print(f"'apple' == 'banana': {'apple' == 'banana'}") # False +print(f"'apple' < 'banana': {'apple' < 'banana'}") # True (按字典序) + +# 链式比较 +z = 7 +print(f"\n链式比较:") +print(f"{y} < {z} < {x}: {y < z < x}") # 5 < 7 < 10: True +print(f"{x} > {z} > {y}: {x > z > y}") # 10 > 7 > 5: True +print(f"{x} == {z} == {y}: {x == z == y}") # False + +# 在上下文中很多用于布尔值 +# Python中的假值 +falsy_values = [ + False, # 布尔假 + None, # 空值 + 0, # 整数零 + 0.0, # 浮点数零 + 0j, # 复数零 + "", # 空字符串 + [], # 空列表 + (), # 空元组 + {}, # 空字典 + set(), # 空集合 +] + +print("假值测试:") +for value in falsy_values: + if value: + print(f"{value!r:10} -> True") + else: + print(f"{value!r:10} -> False") + +# !r是转成字符串 + +# 真值示例 +truthy_values = [ + True, # 布尔真 + 1, # 非零数字 + 0.1, # 非零浮点数 + "hello", # 非空字符串 + [1, 2, 3], # 非空列表 + (1, 2), # 非空元组 + {"key": "value"}, # 非空字典 + {1, 2, 3}, # 非空集合 +] + +print("\n真值测试:") +for value in truthy_values: + if value: + print(f"{value!r:20} -> True") + else: + print(f"{value!r:20} -> False") + +# 应用 +# 条件语句 +age = 20 +has_license = True +has_car = False + +# if 语句 +if age >= 18: + print("已成年") + +# if-else 语句 +if has_license and has_car: + print("可以开车") +else: + print("不能开车") + +# if-elif-else 语句 +score = 85 +if score >= 90: + grade = "A" +elif score >= 80: + grade = "B" +elif score >= 70: + grade = "C" +else: + grade = "D" +print(f"分数 {score} -> 等级 {grade}") + +# 循环 +# while 循环 +count = 0 +while count < 5: + print(f"while循环: count = {count}") + count += 1 + +# break 和 continue +print("\nbreak和continue演示:") +for i in range(10): + if i == 2: + continue # 跳过本次循环 + if i == 7: + break # 终止循环 + print(f"i = {i}") + + +# 布尔函数和操作 +# bool() 函数用于将一个值转换为布尔类型(True 或 False)。在 Python 中,以下情况会被视为 False: + + +# 数值类型的 0(如 0, 0.0, 0j) +# 空序列或空集合(如 "", [], (), {}) +# None +# 自定义对象的 bool 或 len 返回 False 或 0 +# 其他情况都被视为 True。 +# 定义一个函数用于演示bool()函数的用法 +def bool_function(): + # 定义一个包含多种类型测试值的列表 + test_values = [0, 1, -1, 0.0, 0.1, "", "hello", [], [1], None] + + # 打印测试标题 + print("bool()函数测试:") + # 遍历每个测试值 + for value in test_values: + # 打印每个值及其对应的bool()结果 + print(f"bool({value!r:10}) = {bool(value)}") + + +# 调用上面定义的函数 +bool_function() + + +# 定义一个银行账户类,用于演示自定义对象的布尔值 +class BankAccount: + # 初始化方法,设置账户余额 + def __init__(self, balance): + self.balance = balance + + # 定义__bool__方法,余额大于0时对象为True,否则为False + def __bool__(self): + return self.balance > 0 + + # 定义__str__方法,返回账户余额的字符串表示 + def __str__(self): + return f"BankAccount(余额: ${self.balance})" + + +# 打印自定义对象布尔值的测试标题 +print("\n自定义对象布尔值:") +# 创建一个余额为100的账户对象 +account1 = BankAccount(100) +# 创建一个余额为0的账户对象 +account2 = BankAccount(0) + +# 打印第一个账户对象及其bool()结果 +print(f"{account1}: bool() = {bool(account1)}") +# 打印第二个账户对象及其bool()结果 +print(f"{account2}: bool() = {bool(account2)}") + +# any()和all()函数 +# any() 和 all() 是 Python 内置的两个常用函数,用于判断可迭代对象中的元素布尔值。 +# any(iterable): 只要 iterable 中有一个元素为 True(即"真值"),就返回 True;如果所有元素都为 False,则返回 False。 +# all(iterable): 只要 iterable 中有一个元素为 False(即"假值"),就返回 False;只有所有元素都为 True 时才返回 True。 + +# any() 任意一个为True则为True +print( + f"any([False,False,False]):{any([False,False,False])}" +) # any([False,False,False]):False +print( + f"any([False,True,False]):{any([False,True,False])}" +) # any([False,True,False]):True +print(f"any([1,0,1,0]):{any([1,0,1,0])}") # any([1,0,1,0]):True + +# all() 所有是true才为true +print(f"all([True, True, True]): {all([True, True, True])}") # True +print(f"all([True, False, True]): {all([True, False, True])}") # False +print(f"all([1, 1, 0]): {all([1, 1, 0])}") # False + +numbers = [2, 4, 6, 8] +print(all(n % 2 == 0 for n in numbers)) # True +print(any(n % 2 != 0 for n in numbers)) # False diff --git a/13-17/05float.py b/13-17/05float.py new file mode 100644 index 0000000..d0c65b1 --- /dev/null +++ b/13-17/05float.py @@ -0,0 +1,27 @@ +# 什么是浮点数? +# 浮点数是用来表示实数(包含小数点的数)的数据类型。在 Python 中,浮点类型用 float 表示。 +pi = 3.1415926 +temperature = -10.5 +salary = 5000.00 +scientific = 6.02e23 # 科学计数法:6.02 × 10²³ + +# 类型转换 +# 使用float()函数进行类型转换 + +float_form_init = float(40) +print(float_form_init) # 40.0 + +float_form_str = float("99") +print(float_form_str) # 3.14 + +float_form_bool = float(True) +print(float_form_bool) # 1.0 + +float_form_false = float(False) +print(float_form_false) # 0.0 + +# 除法运算会产生浮点数 +result1 = 10 / 2 +print(result1) # 5.0 +result2 = 7 / 2 +print(result2) # 3.5 diff --git a/13-17/06if.py b/13-17/06if.py new file mode 100644 index 0000000..b31fbc3 --- /dev/null +++ b/13-17/06if.py @@ -0,0 +1,68 @@ +# if 语句有三种基本形式:if, if-else, 和 if-elif-else。 +age = 20 +if age >= 18: + print("成年了") + +# if 条件: else: +age = 16 +if age >= 18: + print("成年了") +else: + print("未成年") + + +# 形式三:if-elif-else 语句 +# 用于判断多种可能的情况。程序会按顺序检查每一个 elif 的条件,一旦某个条件为 True,就执行对应的代码块,然后跳出整个 if 结构。如果所有 if 和 elif 的条件都不满足,则执行 else 的代码块。 + +score = 90 +if score >= 90: + print("优秀") +elif score >= 60: + print("及格") +else: + print("不及格") + +# 关键细节 +# 使用缩进来区分代码块 +# 通常使用4个空格作为一个缩进级别 +# 同一个代码块的语句必须相同的缩进 + +# 条件表达式 +# if 后面的“条件”可以是很广泛的表达式,其结果会被判断为 True 或 False。 + +# 比较运算符: == (等于), != (不等于), > (大于), < (小于), >= (大于等于), <= (小于等于) +# 逻辑运算符: and (与), or (或), not (非) +# 成员运算符: in (在...内), not in (不在...内) +age = 25 +is_student = True + +# 使用 and +if age >= 18 and is_student: + print("您是成年学生。") + +# 使用 or +if age < 12 or age >= 65: + print("您可以享受优惠票价。") + +# 使用 not +if not is_student: + print("您不是学生。") + +# 使用 in +name = "Alice" +if name in ["Alice", "Bob", "Charlie"]: + print(f"你好,{name}!") + +# 嵌套的 if 语句 +num = 10 +if num > 0: + print("数字是正数") + if num % 2 == 0: + print("偶数") + else: + print("奇数") +else: + print("数字是0或者负数") + +result = "11" * 2 +print(result) diff --git a/13-17/07while.py b/13-17/07while.py new file mode 100644 index 0000000..5f5ea76 --- /dev/null +++ b/13-17/07while.py @@ -0,0 +1,107 @@ +# while +# while 循环是 Python 中的一种控制流语句,用于在满足特定条件时重复执行一段代码块。只要条件为 True,循环就会一直执行 +# 语法 +# while 条件表达式: +# 循环主体 + +# 示例 +count = 1 +while count < 5: + print(f"这是第{count}次循环") + count += 1 + +# while 循环的关键要素 +# 1.条件表达式 +# 在每次循环开始前检查 +# 如果为 True,执行循环体 +# 如果为 False,退出循环 +# 2.循环体 +# 需要重复执行的代码 +# 必须缩进(通常是4个空格) +# 3.条件更新 +# 必须在循环体内更新条件变量 +# 否则会导致无限循环 + +# 常用场景 +# 计算1~100的和 +sum = 0 +num = 1 +while num <= 100: + sum += num + num += 1 +print(sum) + +# 用户输入验证 +# user_input = input("请输入一个正整数") +# while True: +# if user_input.isdigit() and user_input > 0: +# print(f"您输入的数字是{user_input}") +# break +# else: +# print("输入数字无效") + +fruits = ["苹果", "香蕉", "栗子"] +index = 0 +while index < len(fruits): + print(fruits[index]) + index += 1 + + +# 控制循环的特殊语句 +# break 立刻跳出循环 + +# 寻找第一个能被7整除的数 +num = 1 +while num < 20: + if num % 7 == 0: + print(f"第一个被7整除的数{num}") + break + num += 1 + +# continue 跳过当前,继续下一个 +# 打印0~10之间的奇数 +num = 0 +while num < 10: + num += 1 + if num % 2 == 0: + continue + print(num) + +# else 子句 +# while循环可以有一个else子句 +count = 1 +while count < 3: + print(f"循环第{count}次") + count += 1 +else: + print("循环结束,退出") + +# 案例 +# 猜数 +# import random + +# secret_num = random.randint(1, 10) +# attempts = 0 +# max_attempts = 7 +# while attempts < max_attempts: +# attempts += 1 +# guess = int(input("请输入一个数")) +# if guess < secret_num: +# print("太小了") +# if guess > secret_num: +# print("太大了") +# if guess == secret_num: +# print("恭喜你猜对了") +# break +# else: +# print(f"游戏结束,正确答案是{secret_num}") + + +# 注意事项 +# 避免无限循环:确保循环条件最终会变为 False正确缩进:循环体内的所有代码必须正确缩进 +# 更新条件变量:在循环体内更新影响条件的变量 +# 使用break谨慎:过多的break语句可能使代码难以理解 + + +abc = "Hello" +print(f"abc{'o' in abc}") diff --git a/13-17/08list.py b/13-17/08list.py new file mode 100644 index 0000000..9ef65f8 --- /dev/null +++ b/13-17/08list.py @@ -0,0 +1,257 @@ +# 列表是什么? +# 列表 是一个有序、可变的集合,可以存储任意数量、任意类型的元素。 + +# 有序:元素有固定的位置(索引),按添加的顺序排列。 +# 可变:创建后,可以修改列表的内容(增、删、改)。 +# 异构:一个列表中可以包含不同类型的数据(整数、字符串、甚至其他列表) + +# 创建列表 +# 使用[] +empty_list = [] +print(empty_list) + +number = [1, 2, 3, 4] +mixed = [1, True, "hello"] +print(number) +print(mixed) + +# 使用list()构造函数 +# 创建列表除了用方括号 [],也可以用内置的 list() 函数。 +# list() 可以将其他可迭代对象(如字符串、元组、字典、集合等)转换为列表。 + +# 如果传入一个字符串,每个字符会成为列表中的一个元素。 +# 如果传入一个元组,列表会包含元组中的元素。 +# 如果不传参数,会得到一个空列表。 + +# 字符串 +list_from_string = list("abc") +print(list_from_string) # ['a', 'b', 'c'] + +# 元组 +list_from_tuple = list((1, 2, 3)) +print(list_from_tuple) # [1, 2, 3] + +# 不传 +list_from_empty = list() +print(list_from_empty) # [] + + +# 访问列表元素(索引和切片) +# 索引访问 从0开始 +list_number = [1, 2, 3] +print(list_number[0]) # 1 +print(list_number[-1]) # 3 +# print(list_number[100]) # IndexError: list index out of range + +# 切片访问 +# 切片用于获取列表的一个子集,语法:list[start:stop:step] +# 注意:会创建新列表,不会修改原列表 + +# start:起始索引(包含) +# stop:结束索引(不包含) +# step:步长(默认为1) +numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8] +print(numbers[2:5]) # [2, 3, 4] +print(numbers[:5]) # [0, 1, 2, 3, 4] +print(numbers[5:]) # [ 5, 6, 7, 8] +print(numbers[::2]) # [0, 2, 4, 6, 8] +print(numbers[::-1]) # [8, 7, 6, 5, 4, 3, 2, 1, 0] 反转列表 + +new_numer = numbers[1:4] +print(new_numer) # [1,2,3] + +# 操作 +# 修改元素 +fruits = ["apple", "banana", "cherry"] +fruits[0] = "pick" +print(fruits) # ["pick", "banana", "cherry"] + +# 添加元素 +# append(x) +# 在列表末尾添加一个元素x +# insert(index,x) +# 在指定位置 index 插入元素 x,原有及后续元素后移。 +# extend(iterable) +# 将另一个可迭代对象(如列表、元组等)的元素逐个添加到列表末尾。 +# 注意: +# append() 是把一个元素作为整体添加到末尾 +# extend() 是把所有元素分别添加到原列表 + +# append +a = [1, 2] +a.append([3, 4]) +print(a) # [1, 2, [3, 4]] 会把[3,4] 作为一个整体添加到列表中 + +b = [1, 2] +b.extend([3, 4]) +print(b) # [1, 2, 3, 4] 将[3,4]分别添加到列表中 + +c = [1, 2] +c.insert(1, 3) +print(c) # [1, 3, 2] 往指定位置添加 + + +# 删除 +# 在操作列表时,常常需要删除其中的元素。Python 提供了多种删除列表元素的方法,主要包括: + +# remove(x) 方法 +# 用于删除列表中第一个值为 x 的元素(如果没有这样的元素会抛出 ValueError)。 +# 只会删除找到的第一个匹配项。 +# 语法:list.remove(x) + +# pop([index]) 方法 +# 用于删除并返回给定索引处的元素。如果没有指定索引,默认删除并返回最后一个元素。 +# 如果索引越界会抛出 IndexError。 +# 语法:list.pop() 或 list.pop(index) + +# del 语句 +# del 可以根据索引删除列表的指定元素,也可以一次性删除多个元素(切片)。 +# 语法:del list[index] 或 del list[start:end] +# clear() 方法 + +# 清空整个列表,变成空列表 []。 +# 语法:list.clear() + +# - remove() 删除第一个匹配的元素 +fruits = ["apple", "banana", "cherry", "banana", "date"] +fruits.remove("banana") +print(fruits) # ['apple', 'cherry', 'banana', 'date'] + +# - pop() - 删除指定索引的元素并返回指定索引(默认删除最后一个) +fruits.pop() +print(fruits) # ['apple', 'cherry', 'banana'] +fruits.pop(2) +print(fruits) # ['apple', 'cherry'] + +# - del(index) 按照索引删除 +del fruits[0] +print(fruits) # ['cherry'] + +# - clear() 清空数组 +fruits.clear() +print(fruits) # [] + +# 其他操作 +# 拼接:用加号 + 可以合并两个或多个列表,形成一个新列表,不改变原列表。 +# 重复:用乘号 * 可以将列表重复多次,得到新列表。 +# 成员测试:使用 in 或 not in 快速判断某个元素是否存在于列表中,结果为布尔值。 +# 获取长度:len(lst) 得到列表中的元素数量。 +list1 = [1, 2, 3] +list2 = [4, 5, 6] +list3 = list1 + list2 +print(list3) # [1, 2, 3, 4, 5, 6] +list4 = [7, 8] +list5 = list4 * 2 +print(list5) # [7, 8, 7, 8] +# 检查元素是否存在 +list6 = [9, 10, 11] +print(12 in list6) # False +# 获取列表长度 +print(len(list6)) # 3 + +# sorce()排序 +numbers = [3, 1, 4, 1, 5, 9, 2, 6] +numbers.sort() +print(numbers) # [1, 1, 2, 3, 4, 5, 6, 9] + +# reverse()反转 +numbers.reverse() +print(numbers) # [9, 6, 5, 4, 3, 2, 1, 1] + +# 查找索引index +print(numbers.index(9)) # 0 + +# count() 计数 +print(numbers.count(1)) # 2 + +# copy() 复制 +numbers_copy = numbers.copy() +# 等价于 +# numbers_copy = numbers[:] +# numbers_copy = list[numbers] + +# 列表遍历 +# 直接遍历元素 +fruits = ["apple", "banana", "cherry"] +for fruit in fruits: + print(fruit) + +# 遍历索引和元素 +# 使用 enumerate 可以在遍历列表时同时获得每个元素的索引和值。 +for index, fruit in enumerate(fruits): + print(f"索引{index}的值是{fruit}") + +# 列表推导式 +# 列表推导式(List Comprehensions)是 Python 提供的一种简洁优雅的构造新列表的方法。它既可以替代传统的 for 循环,也可以在创建列表时加入条件判断,让表达更加简明 + +# 语法 +# new_list = [表达式 for 变量 in list] +# 等同于 +# new_list = [] +# for 变量 in list: +# new_list.append(表达式) + +# 可以添加条件的列表推导式 +# new_list = [表达式 for 变量 in list if 条件] + +# 示例 +# 生成偶数数字的平方根 +num = [1, 2, 3, 4] +new_num = [n**2 for n in num if n % 2 == 0] +print(new_num) # [4, 16] + +# 列表推到常用来构建,转换,筛选列表 +# 构建 +squares = [n**2 for n in range(5)] +print(squares) # [0, 1, 4, 9, 16] +# 转换 +fruits = ["Apple", "Banana", "cherry"] +low_list = [f.lower() for f in fruits] +print(low_list) # ['apple', 'banana', 'cherry'] +# 筛选 +num = [1, 2, 3, 4] +new_num = [n**2 for n in num if n % 2 == 0] +print(new_num) # [4, 16] + +# 多维列表 +# 2x3 矩阵(二维列表) +matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + +# 访问元素 +print(matrix[0]) # [1, 2, 3] - 第一行 +print(matrix[1][2]) # 6 - 第二行第三列 + +# 遍历二维列表 +for row in matrix: + for element in row: + print(element, end=" ") + print() # 换行 + +# 输出: +# 1 2 3 +# 4 5 6 +# 7 8 9 + + +# 注意 +# 深,浅拷贝 +# 浅拷贝(shallow copy)和深拷贝(deep copy)是列表复制时的两个概念,尤其是在涉及多维列表(嵌套列表)时需要特别注意。 + +# 浅拷贝:只复制最外层的列表对象,内部的子对象依然引用原来的地址。常用 list.copy()、切片[:] 或 list() 实现。 +# 深拷贝:不仅复制最外层列表,也递归复制所有子对象,互不影响。需要用 copy.deepcopy()(需 import copy)。 + +# 浅拷贝 +a = [[1, 2], [3, 4]] +b = a.copy() +b[1].append(5) +print(a) # [1, 2], [3, 4, 5]] +print(b) # [1, 2], [3, 4, 5]] + +# 深拷贝 +import copy + +c = [[1, 2], [3, 4]] +d = copy.deepcopy(c) +d[1].append(5) +print(c) # [[1, 2], [3, 4]] +print(d) # [[1, 2], [3, 4, 5]] diff --git a/13-17/09tuple.py b/13-17/09tuple.py new file mode 100644 index 0000000..12a6067 --- /dev/null +++ b/13-17/09tuple.py @@ -0,0 +1,102 @@ +# 元组 是一个有序、不可变的集合,可以存储任意数量、任意类型的元素。 + +# 有序:元素有固定的位置(索引),按添加的顺序排列。 +# 不可变:创建后,不能修改元组的内容(不能增、删、改元素)。 +# 异构:一个元组中可以包含不同类型的数据。 +# 核心特性:不可变性是元组与列表最根本的区别! + +# 创建方式 +# 使用() +empty_tuple = () +print(empty_tuple) + +numers = (1, 2, 3, 4, 5) +fruits = ("apple", "banana", "orange") +mixed = ( + "Hello", + 1, + [ + 1, + 2, + ], + True, +) +print(numers) +print(fruits) +print(mixed) + +# 使用tuple构造函数 +# tuple() 是 Python 的一个内置函数,可以把可迭代对象(如列表、字符串、字典、集合等)转化为元组。这种方式更适合在已知有可迭代数据时创建元组,例如将列表转换为元组,或将字符串的每个字符作为元组的一个元素。 + +# 如果不传参数,tuple() 会返回一个空的元组。 +list_data = [1, 2, 3] +tuple_from_list = tuple(list_data) +print(tuple_from_list) # (1, 2, 3) + +tuple_from_string = tuple("abc") +print(tuple_from_string) # ('a', 'b', 'c') + +# 创建空元组 +another_enmpy_tuple = tuple() +print(another_enmpy_tuple) + +# 特殊情况,单个元素的元组 +# 创建单个元素的元组,需要在元组后面加,否则python会认为他是括号表达式 +a_tuple = (1,) +print(a_tuple) + +# 访问元组 +# 通过索引 +fruits = ("apple", "banana", "orange", "grape") + +print(fruits[0]) # "apple" - 第一个元素 +print(fruits[1]) # "banana" - 第二个元素 +print(fruits[-1]) # "grape" - 最后一个元素 +print(fruits[-2]) # "orange" - 倒数第二个元素 + +# 通过切片 +numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + +print(numbers[2:5]) # (2, 3, 4) # 索引2到5(不含5) +print(numbers[:4]) # (0, 1, 2, 3) # 从开始到索引4 +print(numbers[5:]) # (5, 6, 7, 8, 9) # 从索引5到结束 +print(numbers[::2]) # (0, 2, 4, 6, 8) # 每隔一个取一个元素 +print(numbers[::-1]) # (9, 8, 7, 6, 5, 4, 3, 2, 1, 0) # 反转元组 + + +# 元组的不可变 +fruits = ("apple", "banana", "cherry") +# fruits[0] = "abc" # TypeError: 'tuple' object does not support item assignment + +# 如何修改元组 +# 由于元组不可变,不能直接修改,但可以创建新的元组 +# 直接重新赋值 +fruits = ("apple", "banana", "cherry") +fruits = ("apple", "pear", "banana", "cherry") # 重新创建新元组 +print(fruits) # ('apple', 'pear', 'banana', 'cherry') +# 通过拼接 +fruits = ("apple", "banana", "cherry") +new_fruits = fruits[:1] + ("pear",) + fruits[1:] +print(new_fruits) + +# 元组的操作与方法 +# 列表操作类似,元组也支持以下常用操作(但所有操作不会改变原元组,而是产生新元组或返回新结果): + +# 连接(拼接):用加号 + 组合两个元组,得到新元组。 +# 重复:用乘号 * 重复元组若干次,得到新元组。 +# 成员测试:用 in 或 not in 判断元素是否存在于元组中,返回布尔值。 +# 获取长度:len(tuple) 返回元组包含的元素数量。 + +# 拼接 +tuple1 = (1, 2) +tuple2 = (3, 4) +tuple3 = tuple1 + tuple2 +print(tuple3) # (1, 2,3,4) +# 重复 +tuple4 = tuple3 * 2 +print(tuple4) # (1, 2, 3, 4, 1, 2, 3, 4) +# 是否存在 +fruits = ("apple", "banana") +print("apple" in fruits) # True +# 获取长度 +print(len(fruits)) # 2 diff --git a/13-17/lianxi-01xuniji.py b/13-17/lianxi-01xuniji.py new file mode 100644 index 0000000..7e7d251 --- /dev/null +++ b/13-17/lianxi-01xuniji.py @@ -0,0 +1,88 @@ +class SimpleVM: + # 初始化方法 + def __init__(self): + self.stack = [] + self.locals = {} + self.globls = {} + + def load_const(self, const): + # 将常量推到栈中 + self.stack.append(const) + print(f"加载常量: {const} -> 栈: {self.stack}") + + def store_name(self, name): + if not self.stack: + raise RuntimeError("栈为空") + # 取出值 + value = self.stack.pop() + # 存储到字典中 + self.locals[name] = value + print(f"存储变量: {name} = {value}") + + def load_name(self, name): + if name in self.locals: + value = self.locals[name] + elif name in self.globls: + value = self.globls[name] + else: + raise RecursionError(f"name:{name} is not defined") + self.stack.append(value) + print(f"加载变量: {name} = {value} -> 栈: {self.stack}") + + def binary_add(self): + if len(self.stack) < 2: + raise RecursionError("栈中元素不足") + # + a = self.stack.pop() + b = self.stack.pop() + result = a + b + self.stack.append(result) + print(f"加法: {a} + {b} = {result} -> 栈: {self.stack}") + + def return_value(self): + if not self.stack: + return None + value = self.stack.pop() + print(f"返回: {value}") + return value + + +def vm_execution(): + vm = SimpleVM() + # 输出即将执行的代码说明 + print("执行代码: a = 10; b = 20; c = a + b") + # 构造指令序列 + instructions = [ + ("LOAD_CONST", 10), # 加载常量10 + ("STORE_NAME", "a"), # 存储到变量a + ("LOAD_CONST", 20), # 加载常量20 + ("STORE_NAME", "b"), # 存储到变量b + ("LOAD_NAME", "a"), # 加载变量a + ("LOAD_NAME", "b"), # 加载变量b + ("BINARY_ADD",), # 执行加法 + ("STORE_NAME", "c"), # 存储到变量c + ("LOAD_NAME", "c"), # 加载变量c + ("RETURN_VALUE",), # 返回值 + ] + + for instruction in instructions: + # 获取操作嘛 + op = instruction[0] + # 获取操作参数 + args = instruction[1:] if len(instruction) > 1 else [] + # 判断不同指令,来调用不同的方法 + if op == "LOAD_CONST": + vm.load_const(args[0]) + elif op == "STORE_NAME": + vm.store_name(args[0]) + elif op == "LOAD_NAME": + vm.load_name(args[0]) + elif op == "BINARY_ADD": + vm.binary_add() + elif op == "RETURN_VALUE": + result = vm.return_value() + + print(f"最终打印结果c={result}") + + +vm_execution() diff --git a/13-17/lianxi-02student.py b/13-17/lianxi-02student.py new file mode 100644 index 0000000..eebb7c5 --- /dev/null +++ b/13-17/lianxi-02student.py @@ -0,0 +1,291 @@ +def process_student_data(student_info): + """ + 处理学生数据,进行类型转换和验证 + + 参数: + student_info: 字典,包含学生信息 + 格式: {"name": "张三", "age": "20", "score": "85.5", "is_passed": "true"} + + 返回: + 处理后的字典,所有值都转换为正确的Python数据类型 + 如果数据无效,返回None + + 要求: + - name: 转换为字符串,去除首尾空格 + - age: 转换为整数,范围1-100 + - score: 转换为浮点数,范围0.0-100.0 + - is_passed: 转换为布尔值("true"/"false"字符串转为True/False) + - 如果任何转换失败或超出范围,返回None + """ + try: + required_fields = ["name", "age", "score", "is_passed"] + # 校验是否字典中都存在字段 + for field in required_fields: + if field not in student_info: + return None + # 将姓名取出收尾空格 + name = str(student_info["name"]).strip() + if not name: + return None + # 将年龄转为整数,并检查范围 + try: + age = int(student_info["age"]) + if not (1 <= age <= 100): + return None + except (ValueError, TypeError): + return None + # 分数转为浮点型 + try: + score = float(student_info["score"]) + if not (0.0 < score < 100.0): + return None + except (ValueError, TypeError): + return None + + # 处理is_passed + is_passed = str(student_info["is_passed"]).lower() + if is_passed == "true": + is_passed = True + elif is_passed == "false": + is_passed = False + else: + is_passed = None + + return {"name": name, "age": age, "score": score, "is_passed": is_passed} + except Exception: + return None + + +def calculate_and_format_grades(students): + """ + 计算学生成绩等级并格式化输出 + + 参数: + students: 学生信息列表,每个元素是字典 + 格式: [{"name": "张三", "score": 85.5}, ...] + + 返回: + 格式化后的成绩报告字符串 + + 要求: + - 根据分数计算等级:>=90为A,>=80为B,>=70为C,>=60为D,<60为F + - 计算平均分、最高分、最低分 + - 统计各等级人数 + - 使用f-string格式化输出,保留2位小数 + - 输出格式要美观,包含表格样式 + """ + if not students: + return "没有学生数据" + + def get_grade(score): + if score >= 90: + return "A" + elif score >= 80: + return "B" + elif score >= 70: + return "C" + elif score >= 60: + return "D" + else: + return "F" + + student_with_grade = [] + # 学生添加等级 + for student in students: + score = student["score"] + grade = get_grade(score) + # 字段用**来进行解包 + student_with_grade.append({**student, "grade": grade}) + + # 计算平均分 + # 列表式推导 + scores = [s["score"] for s in student_with_grade] + # 计算平均分 + average_score = sum(scores) / len(scores) + # 最高分 + max_score = max(scores) + # 最低分 + min_score = min(scores) + + # 统计每个等级的人数 + grade_counts = {} + for student in student_with_grade: + grade = student["grade"] + grade_counts[grade] = grade_counts.get(grade, 0) + 1 + + # 输出结果 + result = "成绩报告\n" + # 分割线 + result += "=" * 42 + "\n" + # 添加表头 + result += f"{'学生姓名':<10}{'分数':<8}{'等级':<4}\n" + result += "=" * 42 + "\n" + # 格式化输出每个学生的成绩 + for student in student_with_grade: + result += ( + f"{student['name']:<10}{student['score']:<8.2f}{student['grade']:<4}\n" + ) + # 分割线 + result += "=" * 42 + "\n" + # 平均分 + result += f"平均分:{average_score}\n" + # 最高分 + result += f"最高分{max_score}\n" + # 最低分 + result += f"最低分{min_score}\n" + + # 等级分布 + grade_dist = ",".join( + [f"{grade}:{count}人" for grade, count in grade_counts.items()] + ) + result += f"等级分布{grade_dist}\n" + + return result + + +def analyze_student_performance(students, filters=None): + """ + 分析学生表现数据 + + 参数: + students: 学生信息列表 + filters: 筛选条件字典,可选参数 + 格式: {"min_score": 80, "max_score": 95, "grade": "A"} + + 返回: + 分析结果字典,包含: + { + "total_count": 总人数, + "filtered_count": 筛选后人数, + "average_score": 平均分, + "grade_distribution": 等级分布, + "top_performers": 前3名学生, + "pass_rate": 及格率 + } + + 要求: + - 支持按分数范围筛选 + - 支持按等级筛选 + - 计算及格率(>=60分) + - 找出前3名高分学生 + - 处理边界情况(空数据、无效筛选条件等) + """ + # 如果没有筛选数据,返回默认值 + if not filters: + return { + "total_count": 0, + "filtered_count": 0, + "average_score": 0.0, + "grade_distribution": {}, + "top_performers": [], + "pass_rate": 0.0, + } + # 学生总人数 + total_count = len(students) + # 拷贝一份数据 + filter_students = students.copy() + + # 获取当前学生等级 + def get_grade(score): + if score >= 90: + return "A" + elif score >= 80: + return "B" + elif score >= 70: + return "C" + elif score >= 60: + return "D" + else: + return "F" + + # 过滤大于最小分数的学生的学生数据 + if "min_score" in filters: + filter_students = [ + s for s in filter_students if s["score"] >= filters["min_score"] + ] + # 过滤小于最大分数分的学生数据 + if "max_score" in filters: + filter_students = [ + s for s in filter_students if s["score"] <= filters["max_score"] + ] + # 等级筛选 + if "grade" in filters: + filter_grade = filters["grade"] + filter_students = [ + s for s in filter_students if get_grade(s["score"]) == filter_grade + ] + # 筛选后的学生数量 + filter_count = len(filter_students) + # 计算平均分 + if filter_students: + average_score = sum(s["score"] for s in filter_students) / filter_count + else: + average_score = 0.0 + # 统计筛选后的各个等级的人数 + grade_distribution = {} + for student in filter_students: + grade = get_grade(student["score"]) + grade_distribution[grade] = grade_distribution.get(grade, 0) + 1 + + # 针对学生的分数进行排序 + sorted_students = sorted(filter_students, key=lambda x: x["score"], reverse=True) + # 取前三名 + top_performers = sorted_students[:3] + + # 筛选出及格人数 + pass_count = sum(1 for s in filter_students if s["score"] >= 60) + # 计算出及格率 + pass_rate = pass_count / len(filter_students) * 100 if pass_count > 0 else 0.0 + + return { + "total_count": total_count, + "filter_count": filter_count, + "average_score": average_score, + "grade_distribution": grade_distribution, + "top_performers": top_performers, + "pass_rate": pass_rate, + } + + +# 测试数据 +test_students = [ + {"name": " 张三 ", "age": "20", "score": "85.5", "is_passed": "true"}, + {"name": "李四", "age": "19", "score": "92.0", "is_passed": "true"}, + {"name": "王五", "age": "21", "score": "78.3", "is_passed": "false"}, + {"name": "赵六", "age": "22", "score": "65.7", "is_passed": "true"}, + {"name": "钱七", "age": "20", "score": "45.2", "is_passed": "false"}, +] + +# 筛选条件测试 +test_filters = [{"min_score": 80, "max_score": 95}, {"grade": "A"}, {"min_score": 60}] + +# 格式化学生数据 +process_students = [] +for i, student in enumerate(test_students): + processed = process_student_data(student) + if processed: + process_students.append(processed) + print(f"学生{i}:{processed}") + else: + print(f"第{i+1}个学生数据无效") + +# 计算学生成绩与格式化 +if process_students: + grade_report = calculate_and_format_grades(process_students) +print(grade_report) + + +# 测试数据筛选和统计分析 +print("3. 数据筛选与统计:") +# 准备三组不同的筛选条件 +test_filters = [{"min_score": 80}, {"grade": "A"}, {"min_score": 60, "max_score": 90}] + + +# 遍历筛选条件,输出分析结果 +for i, filter_condition in enumerate(test_filters, 1): + print(f"筛选条件{i}:{filter_condition}") + result = analyze_student_performance(process_students, filter_condition) + print(f"总人数{result['total_count']},筛选后的人数{result['filter_count']}") + print(f"平均分{result['average_score']:.2f},及格率:{result['pass_rate']}") + print(f"等级分布{result['grade_distribution']}") + print(f"前三名{[s['name'] for s in result['top_performers']]}") diff --git a/13-17/lianxi-03jiebao.py b/13-17/lianxi-03jiebao.py new file mode 100644 index 0000000..0244b38 --- /dev/null +++ b/13-17/lianxi-03jiebao.py @@ -0,0 +1,23 @@ +data_tuple = (1, 2, 3, 4, 5) +a, *b, c = data_tuple +print(a) +print(b) # [2, 3, 4] +print(c) + +# 收集到一个列表并赋给 b +a, *b, c = 1, 2, 3, 4, 5 +print(a) +print(b) # [2, 3, 4] +print(c) + +# 字典解包 +# 需要** +dict1 = {"a": 1, "b": 2} +dict2 = {"c": 3, "d": 4} +merged_dict = {**dict1, **dict2} +print(merged_dict) # {'a': 1, 'b': 2, 'c': 3, 'd': 4} + + +text = "Hello World" +position = text.find("r") +print(position) diff --git a/13-17/lianxi-04is.py b/13-17/lianxi-04is.py new file mode 100644 index 0000000..15360c5 --- /dev/null +++ b/13-17/lianxi-04is.py @@ -0,0 +1,36 @@ +obj_x = [10, 20] +obj_y = [10, 20] +print(obj_x == obj_y) # True 比较内容 +print(obj_x is obj_y) # False 比较内存地址 + + +# 定义一个列表,并让另一个变量引用它 +obj_p = [30, 40] +obj_q = obj_p # obj_q 引用了 obj_p 所指向的同一个对象 +print(obj_p == obj_q) # True 比较内容 +print(obj_p is obj_q) # True 比较内存地址 + + +# is not None 判断一个变量是否为None +my_variable = None + +if my_variable is not None: + # 如果 my_variable 不是 None,则打印此消息 + print("Variable is not None") +else: + # 如果 my_variable 是 None,则打印此消息 + print("Variable is None") + +# 错误示范:使用 != None 进行比较 +# if my_variable != None: +# 如果 my_variable 不等于 None,则打印此消息 +# print("Variable is not None (using != None)") + + +sum = 0 +for i in range(5): + if i == 2: + continue + sum += i + +print(sum) diff --git a/13-17/lianxi-05namedtuple.py b/13-17/lianxi-05namedtuple.py new file mode 100644 index 0000000..d2f5f6b --- /dev/null +++ b/13-17/lianxi-05namedtuple.py @@ -0,0 +1,148 @@ +# namedtuple是Python标准库collections模块中的一个工厂函数,用于创建具名元组。它允许你像访问对象的属性一样访问元组元素,主要作用是提高代码的可读性和可维护性。 + +# 2.1 主要特点: +# 具名访问:可以通过属性名访问元组元素 +# 索引访问:仍然支持传统的索引访问方式 +# 不可变性:与普通元组一样,创建后不可修改 +# 内存效率:比普通类更节省内存 +# 自描述性:通过字段名提供更好的代码可读性 +""" +from collections import namedtuple + +Point = namedtuple("Point", ["x", "y"]) +p1 = Point(10, 20) +# 通过.的方式访问 +print(p1.x) # 10 +# 像普通元组一样通过索引访问元素 +print(p1[0]) # 10 + + +# 多种创建方式 + +from collections import namedtuple + +# 方式1:使用列表定义字段 +Person1 = namedtuple("Person", ["name", "age", "city"]) +# 创建Person具名元组类 +person1 = Person1("Alice", 25, "New York") +# 创建Person实例 +print(f"方式1 - 列表定义: {person1}") +# 打印方式1的结果 + +# 方式2:使用字符串定义字段(空格分隔) +Person2 = namedtuple("Person", "name age city") +# 创建Person具名元组类 +person2 = Person2("Bob", 30, "London") +# 创建Person实例 +print(f"方式2 - 字符串定义: {person2}") +# 打印方式2的结果 + +# 方式3:使用字符串定义字段(逗号分隔) +Person3 = namedtuple("Person", "name, age, city") +# 创建Person具名元组类 +person3 = Person3("Charlie", 35, "Tokyo") +# 创建Person实例 +print(f"方式3 - 逗号分隔: {person3}") +# 打印方式3的结果 + +# 方式4:使用元组定义字段 +Person4 = namedtuple("Person", ("name", "age", "city")) +# 创建Person具名元组类 +person4 = Person4("David", 28, "Paris") +# 创建Person实例 +print(f"方式4 - 元组定义: {person4}") +# 打印方式4的结果 + +# 打印功能验证标题 +for i, person in enumerate([person1, person2, person3, person4], 1): + # 遍历所有person对象 + print(f"方式{i} - 姓名: {person.name}, 年龄: {person.age}, 城市: {person.city}") + # 打印每个person的属性 +""" + +# namedtuple的高级功能 +# 获取字段信息 +# 类型转换(如转为字典) +# 字段值替换,创建并返回一个新的对象 +# 从字典创建实例 +# 解包 +# 迭代以 +# 类型检查等 +# 导入namedtuple,可以创建带字段名的元组类型 +from collections import namedtuple + +# 定义一个Person具名元组类,包含4个字段:name, age, city, job +Person = namedtuple("Person", ["name", "age", "city", "job"]) + +# 功能1:获取字段信息 +print("1. 字段信息:") +# 打印Person类型的所有字段名 +print(f" 字段名: {Person._fields}") +# 打印字段数量(长度) +print(f" 字段数量: {len(Person._fields)}") + +# 功能2:转换为字典 +print("\n2. 转换为字典:") +# 创建一个Person实例,包含姓名、年龄、城市和职业 +person = Person("Alice", 25, "New York", "Engineer") +# 将Person实例转换为字典 +person_dict = person._asdict() +# 打印原始Person对象 +print(f" 原始对象: {person}") +# 打印转换后的字典 +print(f" 转换后字典: {person_dict}") + +# 功能3:替换字段值 +print("\n3. 替换字段值:") +print(f" 原始对象: {person}") +# 使用_replace方法,替换age和city字段,生成新的Person对象 +new_person = person._replace(age=26, city="Boston") +# 打印替换字段后的新对象 +print(f" 替换后对象: {new_person}") + +# 功能4:从字典创建 +print("\n4. 从字典创建:") +# 定义一个字典,包含Person的所有字段信息 +person_data = {"name": "Bob", "age": 30, "city": "London", "job": "Designer"} +# 使用**运算符,把字典内容作为参数传递,创建Person对象 +person_from_dict = Person(**person_data) +# 打印从字典创建的Person对象 +print(f" 从字典创建: {person_from_dict}") + +# 功能5:解包操作 +print("\n5. 解包操作:") +# 对person对象进行解包,分别赋值给name, age, city, job变量 +name, age, city, job = person +# 打印解包后的结果 +print(f" 解包结果: name={name}, age={age}, city={city}, job={job}") + +# 功能6:迭代操作 +print("\n6. 迭代操作:") +print(" 迭代结果:", end=" ") +for field in person: + print(field, end=" ") +# 打印换行 +print() + +# 功能7:类型检查 +print("\n7. 类型检查:") +# 打印person对象的实际类型 +print(f" 对象类型: {type(person)}") +# 检查person是否属于内置tuple类型 +print(f" 是否为元组: {isinstance(person, tuple)}") +# 检查person是否属于Person类型 +print(f" 是否为Person类型: {isinstance(person, Person)}") + + +# join +# 生成器表达式 +numbers = [1, 2, 3, 4, 5] +# 将数字转换为字符串后连接 +numbers_joined = ", ".join(str(num) for num in numbers) +print("数字列表连接:", numbers_joined) + + +words = ["hello", "world", "python"] +# 将单词转换为大写后连接 +upper_joined = " ".join(word.upper() for word in words) +print("大写单词连接:", upper_joined) diff --git a/13-17/log.txt b/13-17/log.txt new file mode 100644 index 0000000..de9c037 --- /dev/null +++ b/13-17/log.txt @@ -0,0 +1 @@ +重要信息 diff --git a/13-17/optput.txt b/13-17/optput.txt new file mode 100644 index 0000000..9ae4eb7 --- /dev/null +++ b/13-17/optput.txt @@ -0,0 +1,2 @@ +这是写入的文件的内容 +这是第二行内容 diff --git a/20-24/01def.py b/20-24/01def.py new file mode 100644 index 0000000..730e634 --- /dev/null +++ b/20-24/01def.py @@ -0,0 +1,533 @@ +# 函数 +# 语法 +# def function_name(parameters): +# """文档字符串(可选)""" +# # 函数体 +# return value # 可选 +# 组成部分: + +# 函数名:标识函数的名称,遵循变量命名规则 +# 参数列表:括号中的变量名,表示调用时可以传递的值 +# 函数体:缩进的代码块,包含具体的实现逻辑 +# 返回值:通过return语句将结果返回给调用者 + + +# 定义 +# Python要求函数体代码必须缩进(通常为4个空格) +def square(x): + return x**2 + + +print(square(2)) + + +# 可以在函数内部定义文档字符串(docstring),用于描述函数的作用: +def square(x): + """ + 求x的平方 + """ + return x**2 + + +# 参数类型 + + +# 1.位置参数:位置参数是最基本的参数类型,调用函数时按照参数的位置一一对应传递。 +# 特点: +# 参数的顺序很重要,不能颠倒 +# 调用时必须提供所有必需参数 +# 参数按位置顺序赋值 +def add(a, b): + return a + b + + +result = add(1, 2) +print(result) + + +# 2.关键字参数:关键字参数允许你在调用函数时,通过"参数名=值"的形式传递参数,这样参数顺序就可以任意。 +# 优点: +# 不用记住参数顺序 +# 增加代码可读性 +# 很适合带有默认参数的函数 +def student_info(name, age, city): + return f"姓名{name},年龄{age},城市{city}" + + +print(student_info(age=18, name="小明", city="beijing")) + + +# 3.默认参数:默认参数是指在定义函数时为参数提供默认值。在调用函数时,如果对应参数没有传值,则会使用这个默认值。 +# 注意事项: +# 默认参数必须出现在非默认参数之后 +# 默认参数常用于大多数情况下使用同一个值的场景 +def greet(name, msg="Hello"): + print(f"{msg}, {name}!") + + +greet("Alice") # 输出:Hello, Alice! +greet("Bob", msg="Hi") # 输出:Hi, Bob! + + +# 4.可变参数:可变参数用于当函数需要接受不定数量的位置参数时,通过在参数前加*来实现。 +# 特点: +# *args不是必须叫args,但习惯上都叫args +# 所有传入的位置参数被收集到一个元组中 +# 特别适合参数数量不确定时使用 +def show_args(*args): + print(f"参数类型{type(args)}") + print(f"参数内容{args}") + + +show_args(1, 2, 4) # 参数类型 参数内容(1, 2, 4) +show_args([1, 2, 3]) # 参数类型 参数内容([1, 2, 3],) +show_args("123") # 参数类型 参数内容('123',) + + +# 应用 +def make_pizza(*foods): + print("制作一个披萨,添加以下配料:") + for food in foods: + print(f"-{food}") + + +make_pizza("蘑菇", "青椒", "芝士") + + +# 5.关键字可变参数:关键字可变参数允许函数接收任意数量的"关键字参数"。这些参数会被自动收集到一个字典中。 +# **kwargs不是必须叫kwargs,习惯上都这么命名 +# 多余的关键字参数汇集到一个字典里 +# 常用于不确定会传入哪些命名参数时 +def show_kwargs(**kwargs): + print(f"参数类型{type(kwargs)}") + print(f"参数内容{kwargs}") + + +show_kwargs(name="1", age=18) # 参数类型 参数内容{'name': '1', 'age': 18} + + +# 综合 +def demo(a, *args, b=1, **kwargs): + print(f"a:{a}") # a:小明 + print(f"args:{args}") # args:(20, 30) + print(f"b:{b}") # b:北京 + print(f"kwargs:{kwargs}") # kwargs:{'x': '8', 'y': 10} + + +demo("小明", 20, 30, b="北京", x="8", y=10) + + +# 参数解包 +# 在Python中,*和**不仅可以用于函数定义时接收可变参数,还可以用于参数解包。 +def greet(name, age, city): + print(f"姓名: {name}, 年龄: {age}, 城市: {city}") + + +# 使用 * 解包列表 +person_info = ["Alice", 25, "北京"] +greet(*person_info) # 等同于 greet("Alice", 25, "北京") + +# 使用 * 解包元组 +data = ("Bob", 30, "上海") +greet(*data) # 等同于 greet("Bob", 30, "上海") + + +# ** 用于解包字典类型 +def create_profile(name, age, city, occupation): + print(f"姓名: {name}, 年龄: {age}, 城市: {city}, 职业: {occupation}") + + +# 使用 ** 解包字典 +profile_data = {"name": "Charlie", "age": 28, "city": "广州", "occupation": "工程师"} +create_profile(**profile_data) + + +# 混合使用 +def complex_function(a, b, c, d, e): + print(f"a: {a}, b: {b}, c: {c}, d: {d},e:{e}") + + +list_data = [1, 2] +dict_data = {"d": 10, "e": "小明"} + +complex_function(*list_data, True, **dict_data) + + +# 返回值 +# 返回单个值 +def get_formatted_name(first_name, last_name): + full_name = f"{first_name}{last_name}" + return full_name + + +musician = get_formatted_name("张", "三") +print(musician) # 张三 + + +# 返回多个值 +def operate_numbers(a, b): + sum_result = a + b + diff_result = a - b + product_result = a * b + return sum_result, diff_result, product_result + + +# 接收元组 +result = operate_numbers(10, 5) +print(result) # (15, 5, 50) + +# 解包返回值 +sum_val, diff_val, product_val = operate_numbers(10, 5) +print(f"Sum: {sum_val}, Difference: {diff_val}, Product: {product_val}") + + +def create_student_report(name, **scores): + report = {"name": name, "total_score": 0, "subjects": scores} + + for key, score in scores.items(): + print(f"{key}:{score}") + + # # 计算总分 + for score in scores.values(): + report["total_score"] += score + + # # 计算平均分 + report["average"] = report["total_score"] / len(scores) + return report + + +student = create_student_report("Alice", **{"math": 95, "science": 87, "english": 92}) +print(student) + + +# 函数文档和注释 +# 文档字符串(Docstring) +# 文档字符串是紧跟在函数定义后,用三引号包裹的字符串,用于描述函数的用途、参数说明、返回值类型等。 +def calculate_circle_area(radius): + """ + 计算圆的面积 + + 参数: + radius (float): 圆的半径 + + 返回: + float: 圆的面积 + """ + import math + + return math.pi * radius**2 + + +# 查看文档字符串 +print(calculate_circle_area.__doc__) +# 查看函数帮助 +help(calculate_circle_area) + + +# 注释 +# 注释是用#开头的说明性文字,用于解释代码片段的实现思路、注意事项或特殊用途 +def safe_divide(a, b): + """安全的除法函数""" + # 检查除数是否为零 + if b == 0: + return "错误:除数不能为零" + + # 执行除法运算 + result = a / b + return result + + +# 变量作用域 +# 作用域类型 +# 作用域类型 描述 示例 +# 局部作用域 变量在函数内部定义,只能在该函数内部使用 函数内的局部变量 +# 全局作用域 变量在所有函数体外部定义,可以在整个模块里访问 模块级别的变量 +# 嵌套作用域 内部函数可以访问外部函数中的变量 闭包中的外部变量 +# 内置作用域 Python预先定义的内置标识符 len, range, print等 + +# LEGB原则 +# Python采用LEGB原则查找变量: + +# L: Local(本地作用域) +# E: Enclosing(嵌套函数的外部函数作用域) +# G: Global(全局作用域) +# B: Built-in(内置作用域) +name = "全局变量" + + +def outer(): + name = "外部函数变量" + + def inner(): + name = "内部函数变量" + print(f"inner:{name}") # 输出"内部函数变量" + + inner() + print(f"outer:{name}") # 输出"外部函数变量" + + +outer() +print(name) # 输出"全局变量" + +# global关键字 +# global关键字允许我们在函数内部声明某个变量为全局变量,从而可以在函数内部修改它。 +# 注意事项: +# 没有global关键字时,在函数内对一个变量赋值会将其作为局部变量处理 +# 使用global后,函数内的变量就直接引用外部全局变量 +counter = 0 + + +def increment(): + global counter # 引用外部全局变量 + counter += 1 + + +increment() +increment() +print(counter) # 2 + + +# nonlocal关键字 +# nonlocal关键字用于在嵌套函数中声明变量来自最近的一层非全局作用域(外层函数)。 + + +def outer(): + x = "local" + + def inner(): + nonlocal x # 声明 x 来自外层作用域 + x = "nonlocal" + print(f"inner:{x}") # inner:nonlocal + + inner() + print(f"outer:{x}") # outer:nonlocal + + +outer() + + +# 高级函数特性 +# 8.1.函数作为参数 +# 函数不仅可以像变量一样赋值给其他变量,还可以作为参数传递给其他函数。 +def apply_operation(numbers, operation): + """对数字列表应用操作""" + return [operation(x) for x in numbers] + + +def square(x): + return x**2 + + +def double(x): + return x * 2 + + +numbers = [1, 2, 3, 4, 5] +squared = apply_operation(numbers, square) +doubled = apply_operation(numbers, double) + +print(squared) # [1, 4, 9, 16, 25] +print(doubled) # [2, 4, 6, 8, 10] + + +# 嵌套函数 +# 嵌套函数是指在一个函数内部定义另一个函数。内部函数可以访问外部函数的参数和局部变量。 +# 用途: +# 实现闭包(closure) +# 将某些逻辑封装到本地作用域 +# 作为工厂函数创建带记忆的数据 +def greet(name): + def format_message(): + return f"Hello, {name}!" + + return format_message() + + +print(greet("Alice")) # Hello, Alice! + + +# 闭包 +# 闭包是指一个函数可以"记住"它被创建时的环境,即使在其外部函数已经执行完毕后,内部函数依然能够访问其外部作用域的变量。 +# 特点: +# 内部函数引用了外部函数的局部变量 +# 外部函数返回内部函数 +# 内部函数可以访问外部函数的变量,即使外部函数已经执行完毕 + + +def make_multiplier(factor): + def multiplier(x): + return x * factor + + return multiplier + + +double = make_multiplier(2) +triple = make_multiplier(3) + +print(double(5)) # 10 +print(triple(5)) # 15 + + +# 装饰器 +# 装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器常用于在不修改原函数代码的情况下,动态地为其添加新功能。 +def my_decorator(func): + def wrapper(): + print("函数执行前") + func() + print("函数执行后") + + return wrapper + + +@my_decorator +def say_hello(): + print("Hello") + + +say_hello() # 函数执行前 Hello 函数执行后 + + +# 带参数的装饰器 +def logger(func): + def wrapper(*args, **kwargas): + print(f"调用函数{func.__name__},参数:{args}{kwargas}") + return func(*args, **kwargas) + + return wrapper + + +@logger +def add(x, y, **kwargs): + a = x + y + b = sum(kwargs.values()) + return a + b + + +print(add(1, 2, a=3, b=4)) + + +# 匿名函数 (Lambda) +# 匿名函数(lambda表达式)是一种快速定义简单函数的方法,通常用于一些无需命名、只用一次的小函数场景。 +# lambda 参数1, 参数2, ... : 表达式 +# 基本 lambda 函数 +# 特点: +# 只能包含表达式,不能包含语句 +# 自动返回表达式的值 +# 适合简单的函数逻辑 +square = lambda x: x**2 +print(square(5)) # 25 + +# 在排序中使用 +students = [ + {"name": "Alice", "grade": 85}, + {"name": "Bob", "grade": 92}, + {"name": "Charlie", "grade": 78}, +] + +# 按成绩排序 +sorted_students = sorted(students, key=lambda x: x["grade"]) +print(sorted_students) + +# 在 map 中使用 +numbers = [1, 2, 3, 4, 5] +squared = list(map(lambda x: x**2, numbers)) +print(squared) # [1, 4, 9, 16, 25] + +# 在 filter 中使用 +even_numbers = list(filter(lambda x: x % 2 == 0, numbers)) +print(even_numbers) # [2, 4] + + +# 递归函数 +# 递归函数是函数调用自身来解决问题的方法,适合解决可以被分解为规模更小、相似子问题的任务。 +# def func(params): +# if 终止条件: +# return 结果 +# else: +# # 递归调用自身 +# return func(更小规模的参数) +# 注意事项: +# 必须设置基线条件(终止条件),避免无限递归 +# 递归深度有限制,可能导致栈溢出 +# 对于规模较大的问题效率较低 +def factorial(n): + """计算阶乘的递归函数""" + if n == 0 or n == 1: + return 1 + else: + return n * factorial(n - 1) + + +print(factorial(5)) # 120 + + +def fibonacci(n): + """计算斐波那契数列""" + if n <= 1: + return n + else: + return fibonacci(n - 1) + fibonacci(n - 2) + + +for i in range(10): + print(fibonacci(i), end=" ") # 0 1 1 2 3 5 8 13 21 34 + + +# 错误处理 +# 在函数中进行错误处理可以提升程序的健壮性和用户体验。 +# def 函数名(参数): +# try: +# # 可能抛出异常的操作 +# except 异常类型1: +# # 异常类型1的处理代码 +# except 异常类型2: +# # 异常类型2的处理代码 +# else: +# # 没有发生异常时的代码 +# finally: +# # 无论是否发生异常都执行 +def safe_divide(a, b): + """安全的除法函数""" + try: + result = a / b + except ZeroDivisionError: + return "错误:除数不能为零" + except TypeError: + return "错误:参数类型不正确" + else: + return result + + +print(safe_divide(10, 2)) # 5.0 +print(safe_divide(10, 0)) # 错误:除数不能为零 +print(safe_divide(10, "a")) # 错误:参数类型不正确 + + +# 最佳实践 +# 14.1.函数设计原则 +# 单一职责:每个函数只做一件事 +# 描述性命名:使用有意义的函数名 +# 保持简短:函数应该简短且专注 +# 使用文档字符串:为函数添加适当的文档 +# 避免副作用:函数不应该修改外部状态,除非明确需要 +# 14.2.参数设计 +# 合理使用默认参数:使函数更灵活 +# 参数顺序:位置参数在前,默认参数在后 +# 使用*args和kwargs**:提高函数灵活性 +# 参数验证:在函数开始处验证参数 +# 14.3.错误处理 +# 处理异常:在适当的地方处理可能的错误 +# 提供有意义的错误信息:帮助用户理解问题 +# 使用try-except:优雅地处理异常情况 +# 14.4.性能考虑 +# 避免不必要的计算:将重复计算提取到函数外部 +# 使用生成器:对于大数据集使用生成器函数 +# 缓存结果:对于昂贵的计算考虑缓存 +# 15.总结 +# 函数是Python编程的核心概念,掌握函数的定义、调用、参数传递、返回值、作用域等概念对于编写高质量的Python代码至关重要。通过合理使用函数,我们可以: + +# 提高代码的可重用性和可维护性 +# 实现模块化编程 +# 简化复杂问题的解决 +# 提高代码的可读性和可测试性 +# 掌握函数的高级特性如闭包、装饰器、递归等,能够让我们编写更加灵活和强大的Python程序。 diff --git a/20-24/02neizhihanshu.py b/20-24/02neizhihanshu.py new file mode 100644 index 0000000..e1a3d23 --- /dev/null +++ b/20-24/02neizhihanshu.py @@ -0,0 +1,362 @@ +# 内置函数 +# python提供了丰富的内置函数,这些函数无需导入任何模块即可直接使用。内置函数涵盖了数学运算、类型转换、序列操作、输入输出等各个方面,是Python编程的基础工具。 +# 分类 主要函数 用途 +# 数学运算 abs(), round(), pow(), max(), min() 数值计算 +# 类型转换 int(), float(), str(), bool(), list() 数据类型转换 +# 序列操作 len(), sum(), sorted(), reversed() 序列处理 +# 输入输出 print(), input() 用户交互 +# 迭代器 range(), enumerate(), zip(), map() 迭代处理 +# 对象操作 type(), isinstance(), hasattr() 对象检查 + +# 基本数学函数 +# abs() - 返回绝对值 +print(abs(-5)) # 5 +print(abs(3.14)) # 3.14 + +# round() - 四舍五入 +print(round(3.14159, 2)) # 3.14 +print(round(3.5)) # 4 + +# pow() - 幂运算 +print(pow(2, 3)) # 8 +print(pow(2, 3, 5)) # 3 (2^3 % 5) + +# divmod() - 返回商和余数 +quotient, remainder = divmod(10, 3) +print(quotient, remainder) # 3 1 + +# 最值函数 +# max() / min() - 最大值/最小值 +numbers = [1, 5, 2, 8, 3] +print(max(numbers)) # 8 +print(min(numbers)) # 1 + +# 支持多个参数 +print(max(1, 5, 3)) # 5 +print(min(1, 5, 3)) # 1 + +# 支持字符串比较 +print(max("abcXYZ")) # 'c'(按Unicode顺序) +print(min("abcXYZ")) # 'X' + + +# 基本类型转换 +# int(), float(), str(), bool() +print(int("123")) # 123 +print(float("3.14")) # 3.14 +print(str(456)) # "456" +print(bool(0)) # False +print(bool(1)) # True +print(bool("")) # False +print(bool("hello")) # True + + +# 集合类型转换 +# list(), tuple(), set(), dict() +print(list("hello")) # ['h', 'e', 'l', 'l', 'o'] +print(tuple([1, 2, 3])) # (1, 2, 3) +print(set([1, 2, 2, 3])) # {1, 2, 3} (自动去重) + +# dict() 转换 +pairs = [("a", 1), ("b", 2)] +print(dict(pairs)) # {'a': 1, 'b': 2} + +# 特殊转换函数 +# chr() / ord() - 字符与ASCII码转换 +print(chr(65)) # 'A' +print(ord("A")) # 65 + +# bin(), oct(), hex() - 进制转换 +print(bin(10)) # '0b1010' +print(oct(10)) # '0o12' +print(hex(255)) # '0xff' + + +# 长度和统计 +# len() - 获取序列长度 +print(len("python")) # 6 +print(len([10, 20, 30])) # 3 +print(len({"a": 1, "b": 2})) # 2 + +# sum() - 求和 +scores = [80, 90, 75] +print(sum(scores)) # 245 +print(sum([1, 2, 3], 10)) # 16 (可指定初始值) + + +# 排序和反转 +# sorted() - 返回排序后的新列表 +letters = ["b", "d", "a", "c"] +print(sorted(letters)) # ['a', 'b', 'c', 'd'] +print(sorted(letters, reverse=True)) # ['d', 'c', 'b', 'a'] + +# reversed() - 生成反向迭代器 +nums = [1, 2, 3] +for n in reversed(nums): + print(n, end=" ") # 输出: 3 2 1 +print(list(reversed(nums))) # [3, 2, 1] + + +# 枚举和打包 +# enumerate() - 枚举索引和元素 +foods = ["apple", "banana", "pear"] +for idx, food in enumerate(foods): + print(idx, food) # 0 apple, 1 banana, 2 pear + +# zip() - 并行打包多个序列 +names = ["Tom", "Jerry"] +ages = [8, 9] +for name, age in zip(names, ages): + print(f"{name} is {age} years old") + +# 逻辑判断 +# any() / all() - 逻辑判断 +flags = [True, False, True] +print(any(flags)) # True,只要有一个为True返回True +print(all(flags)) # False,全部为True才返回True + +# 实际应用 +scores = [80, 70, 65, 90] +print(all(s > 60 for s in scores)) # 检查是否都及格 -> True +print(any(s < 60 for s in scores)) # 是否有挂科 -> False + + +# input() 函数 +# input() 从标准输入(通常为键盘)获取用户输入,返回字符串类型。 +# 注意事项: +# input() 返回的始终是字符串 +# 需要数字时要用 int() 或 float() 转换 +# 可以显示提示信息 +# 基本用法 +name = input("请输入你的名字: ") +print(f"你好, {name}!") + +# 类型转换 +age = int(input("请输入你的年龄: ")) +print(f"你明年就 {age + 1} 岁了!") + + +# print() 向标准输出(控制台)打印内容,支持多种格式参数。 +# 基本语法:print(value1, value2, ..., sep="分隔符", end="结束符") +print("Python", "很", "好用", sep="--") # 输出: Python--很--好用 +print("Hello", end="!") # 输出: Hello! + +# 格式化输出 +x = 5 +print(f"x 的平方是 {x**2}") # 输出: x 的平方是 25 + +# 输出变量和表达式 +numbers = [1, 2, 3] +print("列表:", numbers) # 输出: 列表: [1, 2, 3] + +# range() 函数 +# range() 生成连续整数序列,返回可迭代对象(不是列表)。 +# 基本用法 +# 语法: + +# range(stop):从 0 开始,到 stop(不包含 stop) +# range(start, stop):从 start 开始,到 stop(不包含 stop) +# range(start, stop, step):从 start 开始,步长为 step +# 注意事项: + +# Python 3 中,range() 返回的不是列表 +# 需要用 list(range(...)) 转换为列表 +# stop 不包含在结果序列内 +for i in range(5): + print(i, end=" ") # 输出: 0 1 2 3 4 + +for i in range(3, 8): + print(i, end=" ") # 输出: 3 4 5 6 7 + +for i in range(0, 10, 2): + print(i, end=" ") # 输出: 0 2 4 6 8 + +for i in range(5, 0, -2): + print(i, end=" ") # 输出: 5 3 1 + +# enumerate() 函数 +# enumerate(iterable, start=0) 返回枚举对象,包含索引和值。 +fruits = ["apple", "banana", "cherry"] +for i, fruit in enumerate(fruits): + print(i, fruit) +# 输出: +# 0 apple +# 1 banana +# 2 cherry + +# 自定义起始索引 +for i, fruit in enumerate(fruits, start=1): + print(i, fruit) +# 输出: +# 1 apple +# 2 banana +# 3 cherry + +# zip() 函数 +# zip(*iterables) 并行遍历多个可迭代对象,将相同位置的元素打包成元组。 + + +# zip() 函数 +# zip(*iterables) 并行遍历多个可迭代对象,将相同位置的元素打包成元组。 +# 注意事项: + +# 如果传入的可迭代对象长度不同,则以最短的为准 +# 多余的元素被忽略 +names = ["Tom", "Jerry", "Spike"] +scores = [95, 98, 88] +for name, score in zip(names, scores): + print(name, score) +# 输出: +# Tom 95 +# Jerry 98 +# Spike 88 + +# 序列解包 +pairs = [("a", 1), ("b", 2), ("c", 3)] +letters, numbers = zip(*pairs) +print(letters) # ('a', 'b', 'c') +print(numbers) # (1, 2, 3) + + +# map() 函数 +# map(func, iterable) 对可迭代对象的每个元素应用函数,返回新的迭代器。 +# 将字符串转换为大写 +words = ["hello", "world", "python"] +upper_words = list(map(str.upper, words)) +print(upper_words) # ['HELLO', 'WORLD', 'PYTHON'] + +# 使用lambda函数 +numbers = [1, 2, 3, 4] +squared = list(map(lambda x: x**2, numbers)) +print(squared) # [1, 4, 9, 16] + + +# filter() 函数 +# filter(func, iterable) 筛选出使函数返回 True 的元素,返回新的迭代器。 +# 过滤出长度大于5的单词 +words = ["apple", "banana", "cat", "elephant"] +long_words = list(filter(lambda w: len(w) > 5, words)) +print(long_words) # ['banana', 'elephant'] + +# 过滤出偶数 +numbers = [1, 2, 3, 4, 5, 6] +evens = list(filter(lambda x: x % 2 == 0, numbers)) +print(evens) # [2, 4, 6] +# 注意事项: + +# map 和 filter 都返回迭代器 +# 需要用 list() 或 for 循环取出结果 +# 常与 lambda 表达式配合使用 + + +# reversed() 函数 +# 反向遍历 +for c in reversed("abcde"): + print(c, end=" ") # e d c b a + +# 转换为列表 +nums = [1, 2, 3] +reversed_nums = list(reversed(nums)) +print(reversed_nums) # [3, 2, 1] + + +# sorted() 函数 +# sorted(iterable, key=None, reverse=False) 返回排序后的新列表,不修改原数据。 +# 基本排序 +numbers = [3, 1, 4, 1, 5] +print(sorted(numbers)) # [1, 1, 3, 4, 5] + +# 自定义排序 +nums = [-3, 2, 1, -5] +print(sorted(nums, key=abs)) # [1, 2, -3, -5] (按绝对值排序) +print(sorted(nums, key=abs, reverse=True)) # [-5, -3, 2, 1] + +# 字符串排序 +words = ["apple", "banana", "cherry", "date"] +print(sorted(words, key=len)) # ['date', 'apple', 'banana', 'cherry'] (按长度排序) + + +# 类型检查函数 +# type() - 获取对象类型 +print(type("hello")) # +print(type([1, 2, 3])) # + +# isinstance() - 检查对象类型 +print(isinstance(5, int)) # True +print(isinstance(5, float)) # False +print(isinstance(5, (int, float))) # True (支持类型元组) + + +# 属性操作函数 +class Student: + def __init__(self, name): + self.name = name + + +s = Student("Tom") + +# hasattr() - 检查对象是否有指定属性 +print(hasattr(s, "name")) # True +print(hasattr(s, "age")) # False + +# getattr() - 获取对象属性值 +print(getattr(s, "name")) # Tom +print(getattr(s, "age", "N/A")) # N/A (提供默认值) + +# setattr() - 设置对象属性 +setattr(s, "age", 20) +print(s.age) # 20 + +# delattr() - 删除对象属性 +delattr(s, "age") +print(hasattr(s, "age")) # False + +# 其他 +# callable() - 检查对象是否可调用 +print(callable(print)) # True +print(callable(len)) # True +print(callable(10)) # False + +# dir() - 返回对象的所有属性列表 +print(dir(s)) # 显示s的所有属性和方法名 + +# vars() - 返回对象的属性字典 +print(vars(s)) # {'name': 'Tom'} + +# id() - 返回对象的唯一标识 +print(id(s)) # 内存地址 + +# bool() - 转换为布尔值 +print(bool([1, 2, 3])) # True +print(bool([])) # False +print(bool(0)) # False +print(bool("hello")) # True + + +# reduce() 函数 +# reduce(func, iterable[, initial]) 对可迭代对象执行累积计算,需要从 functools 导入。 +from functools import reduce + +numbers = [1, 2, 3, 4] + +# 连乘:1*2*3*4 +product = reduce(lambda x, y: x * y, numbers) +print(product) # 24 + +# 连加:1+2+3+4 +total = reduce(lambda x, y: x + y, numbers) +print(total) # 10 + +# 带初始值 +result = reduce(lambda x, y: x + y, numbers, 10) +print(result) # 20 (10 + 1 + 2 + 3 + 4) + +# 函数式编程组合 +# 链式使用内置函数 +numbers = [5, 2, 8, 1, 9, 3] +result = sorted(filter(lambda x: x > 3, numbers)) +print(result) # [5, 8, 9] + +# 使用生成器表达式 +total = sum(x * 2 for x in numbers if x % 2 == 0) +print(total) # 20 diff --git a/20-24/03tuidaoshi.py b/20-24/03tuidaoshi.py new file mode 100644 index 0000000..6fcc4e6 --- /dev/null +++ b/20-24/03tuidaoshi.py @@ -0,0 +1,142 @@ +# 导式是Python中一种简洁、高效的创建数据结构的方法,可以用更少的代码生成列表、字典、集合等。推导式让代码更加简洁、可读性更强,同时性能通常比传统循环更好 +# 推导式的优势 +# 优势 描述 示例 +# 代码简洁 用一行表达式完成循环与条件判断 [x**2 for x in range(5)] +# 可读性强 结构清晰,表达意图明确 比传统for循环更直观 +# 性能优越 通常比循环+append更快 底层优化实现 +# 功能丰富 支持条件过滤、嵌套循环等 复杂数据处理 +# 2.2.推导式类型 +# 类型 语法 结果类型 示例 +# 列表推导式 [expr for item in iterable] list [x**2 for x in range(5)] +# 字典推导式 {key: value for item in iterable} dict {x: x**2 for x in range(5)} +# 集合推导式 {expr for item in iterable} set {x**2 for x in range(5)} +# 生成器表达式 (expr for item in iterable) generator (x**2 for x in range(5)) + +# 基本语法 +# [表达式 for 变量 in 可迭代对象 (可选的if条件)] +# 组成部分: +# 表达式:对每个元素进行处理的代码 +# for 变量 in 可迭代对象:遍历数据源 +# if 条件:可选的过滤条件 + +# 列表推导式 +squares = [x**2 for x in range(5)] +print(squares) # [0, 1, 4, 9, 16] + +# 带条件 +# 只包含偶数的平方 +even_squares = [x**2 for x in range(10) if x % 2 == 0] +print(even_squares) # [0, 4, 16, 36, 64] + +# 多个条件 +numbers = [x for x in range(20) if x % 2 == 0 if x % 3 == 0] +print(numbers) # [0, 6, 12, 18] + +# 条件表达式(三元运算符) +results = [x if x % 2 == 0 else "odd" for x in range(5)] +print(results) # [0, 'odd', 2, 'odd', 4] + +# 嵌套循环 +# 二维列表展开 +matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +flattened = [num for row in matrix for num in row] +print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9] + +# 等价于: +flattened = [] +for row in matrix: + for num in row: + flattened.append(num) + +# 创建乘法表 +multiplication_table = [[i * j for j in range(1, 6)] for i in range(1, 6)] +print(multiplication_table) +# [[1, 2, 3, 4, 5], +# [2, 4, 6, 8, 10], +# [3, 6, 9, 12, 15], +# [4, 8, 12, 16, 20], +# [5, 10, 15, 20, 25]] + + +# 字典推导式 +# {键表达式: 值表达式 for 变量 in 可迭代对象 (可选的if条件)} +# 最基础的字典推导式 +d = {x: x**2 for x in range(5)} +print(d) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} + +# 带条件的字典推导式 +d = {x: x**2 for x in range(5) if x % 2 == 0} +print(d) # {0: 0, 2: 4, 4: 16} + + +# 集合推导式 +# {表达式 for 变量 in 可迭代对象 (可选的if条件)} +# 创建唯一平方数的集合 +squares_set = {x**2 for x in range(-5, 6)} +print(squares_set) # {0, 1, 4, 9, 16, 25} + +# 从列表去重 +words = ["hello", "world", "hello", "python", "world"] +unique_words = {word for word in words} +print(unique_words) # {'hello', 'world', 'python'} + +# 带条件的集合推导式 +even_squares = {x**2 for x in range(10) if x % 2 == 0} +print(even_squares) # {0, 64, 4, 36, 16} + +# 生成器表达式 +# (表达式 for 变量 in 可迭代对象 (可选的if条件)) +# 生成器表达式 +squares_gen = (x**2 for x in range(5)) +print(squares_gen) # at 0x...> + +# 转换为列表 +print(list(squares_gen)) # [0, 1, 4, 9, 16] + +# 带条件的生成器表达式 +even_squares_gen = (x**2 for x in range(10) if x % 2 == 0) +print(list(even_squares_gen)) # [0, 4, 16, 36, 64] + + +# 多层嵌套推导式 +# 三维嵌套列表展平 +three_d = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] +flattened_3d = [num for matrix in three_d for row in matrix for num in row] +print(flattened_3d) # [1, 2, 3, 4, 5, 6, 7, 8] + +# 使用字典推导式创建嵌套字典 +nested_dict = { + f"group_{i}": {f"item_{j}": i * j for j in range(1, 4)} for i in range(1, 4) +} +print(nested_dict) +# {'group_1': {'item_1': 1, 'item_2': 2, 'item_3': 3}, +# 'group_2': {'item_1': 2, 'item_2': 4, 'item_3': 6}, +# 'group_3': {'item_1': 3, 'item_2': 6, 'item_3': 9}} + +# 复杂条件逻辑 +# 复杂条件筛选 +numbers = range(20) +complex_filter = [ + x for x in numbers if (x % 2 == 0 and x < 10) or (x % 3 == 0 and x > 10) +] +print(complex_filter) # [0, 2, 4, 6, 8, 12, 15, 18] + + +# 使用函数进行复杂判断 +def is_prime(n): + if n < 2: + return False + for i in range(2, int(n**0.5) + 1): + if n % i == 0: + return False + return True + + +# 筛选素数 +primes = [x for x in range(2, 30) if is_prime(x)] +print(primes) # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + + +numbers = [1, 2, 4] +abc = list(map(lambda x: x * 2, numbers)) +print(abc) diff --git a/20-24/04deidaiqi.py b/20-24/04deidaiqi.py new file mode 100644 index 0000000..4e20eb2 --- /dev/null +++ b/20-24/04deidaiqi.py @@ -0,0 +1,509 @@ +# 迭代器是 Python 中用于遍历数据集合的工具,它提供了一种统一、高效的方式来访问各种数据结构中的元素。 + +# 1.1.什么是迭代器? +# 迭代器是一个实现了迭代协议的对象,具有以下特征: + +# 迭代协议:必须实现 __iter__() 和 __next__() 方法 +# __iter__():返回迭代器对象本身,使对象可以被 iter() 调用 +# __next__():返回下一个元素,如果没有更多元素则抛出 StopIteration 异常 +# 惰性求值:按需生成元素,不预计算所有值,节省内存 +# 状态保持:记住当前的遍历位置 +# 单向遍历:只能向前遍历,不能后退或重复 + +# 迭代器 vs 可迭代对象 +# 理解迭代器和可迭代对象的区别很重要: + +# 可迭代对象 (Iterable):可以被迭代的对象,如列表、元组、字符串等 +# 迭代器 (Iterator):实际执行迭代的对象,实现了 __next__() 方法 +# 重要说明: +# 可迭代对象可以通过 iter() 函数转换为迭代器 +# 迭代器只能使用一次,遍历完后需要重新创建 +# 大多数内置容器类型(如 list、tuple、dict)都是可迭代对象,但不是迭代器 +from collections.abc import Iterable, Iterator + +# 列表是可迭代对象,但不是迭代器 +numbers = [1, 2, 3] +print(isinstance(numbers, Iterable)) # True +print(isinstance(numbers, Iterator)) # False + +# 通过 iter() 获取迭代器 +numbers_iterator = iter(numbers) +print(isinstance(numbers_iterator, Iterator)) # True + + +# 迭代器协议 +# 迭代器协议是 Python 中定义迭代器行为的标准,任何对象只要实现了这个协议,就可以被用于迭代。 + +# 2.1.必须实现的方法 +# 要成为一个合格的迭代器,必须实现以下两个方法: + +# __iter__() 方法 + +# 返回迭代器对象自身 +# 使对象可以被 for 循环或 iter() 调用 +# 通常实现为 return self +# __next__() 方法 + + +# 返回下一个元素 +# 如果没有更多元素,必须抛出 StopIteration 异常 +# 这是迭代器的核心逻辑 +def __iter__(self): + return self + + +def __next__(self): + # 实现具体的迭代逻辑 + # 如果没有更多元素,抛出 StopIteration + pass + + +# 协议特点: + +# 任何实现了这两个方法的对象都可以用于 for 循环 +# 支持 next() 函数调用 +# 可以与 enumerate()、zip() 等内置函数配合使用 + + +# 完整示例 +class MyIterator: + """自定义迭代器示例""" + + def __init__(self, data): + self.data = data + self.index = 0 + + def __iter__(self): + """返回迭代器自身""" + return self + + def __next__(self): + """返回下一个元素""" + if self.index >= len(self.data): + raise StopIteration + value = self.data[self.index] + self.index += 1 + return value + + +# 使用自定义迭代器 +my_iter = MyIterator([1, 2, 3]) +for item in my_iter: + print(item) # 输出: 1, 2, 3 + +# 也可以手动调用 next() +my_iter2 = MyIterator(["a", "b", "c"]) +print(next(my_iter2)) # 'a' +print(next(my_iter2)) # 'b' +print(next(my_iter2)) # 'c' +# print(next(my_iter2)) # 抛出 StopIteration 异常 + + +# 3.创建迭代器的方法 +# 3.1.方法1:实现迭代器类 +# 通过定义一个类并实现迭代器协议来创建自定义迭代器: +class Countdown: + """倒计时迭代器""" + + def __init__(self, start): + self.current = start + + def __iter__(self): + return self + + def __next__(self): + if self.current <= 0: + raise StopIteration + value = self.current + self.current -= 1 + return value + + +# 使用倒计时迭代器 +countdown = Countdown(5) +for number in countdown: + print(number, end=" ") # 输出: 5 4 3 2 1 +# 适用场景: +# 需要复杂的状态管理 +# 需要实现特殊的迭代逻辑 +# 需要封装复杂的迭代行为 + + +# 方法2:使用生成器函数 +# 生成器是一种特殊的迭代器,使用 yield 关键字创建,代码更简洁且内存效率更高: +def simple_gen(): + """简单的生成器函数""" + print("First yield") + yield 1 + print("Second yield") + yield 2 + print("Done") + + +# 创建生成器对象 +g = simple_gen() +print(next(g)) # 输出: First yield \n 1 +print(next(g)) # 输出: Second yield \n 2 +# print(next(g)) # 会引发 StopIteration 异常 + +# 生成器可以用 for 循环遍历 +for value in simple_gen(): + print(f"Got: {value}") + +# 生成器的优势: + +# 代码更简洁,不需要实现 __iter__() 和 __next__() 方法 +# 自动管理状态,无需手动维护索引 +# 内存效率高,按需生成值 +# 支持复杂的控制流(如异常处理、资源管理) + + +# 方法3:使用生成器表达式 +# 生成器表达式是创建迭代器最简洁的方式,语法类似列表推导式,但使用圆括号: +# 基本语法 +# (expression for item in iterable [if condition]) +# 创建平方数生成器 +squares = (x**2 for x in range(5)) +print(list(squares)) # [0, 1, 4, 9, 16] + +# 带条件的生成器表达式 +even_squares = (x**2 for x in range(10) if x % 2 == 0) +print(list(even_squares)) # [0, 4, 16, 36, 64] + +# 手动迭代 +gen = (x * 2 for x in range(3)) +print(next(gen)) # 0 +print(next(gen)) # 2 +print(next(gen)) # 4 +# print(next(gen)) # StopIteration +# 生成器表达式的优势: + +# 语法简洁,一行代码创建迭代器 +# 内存效率高,惰性求值 +# 适合简单的数据转换和过滤 +# 可以与其他迭代器函数链式组合 + +# 内置迭代器工具 +# Python 提供了许多内置函数来操作迭代器,这些工具让迭代操作更加灵活和高效。 + +# 4.1.iter() 和 next() 函数 +# 这两个函数是操作迭代器的基础工具: + +# iter(iterable):将可迭代对象转换为迭代器 +# next(iterator):获取迭代器的下一个元素 +# next(iterator, default):获取下一个元素,如果迭代结束则返回默认值 + +# 创建迭代器 +numbers = [1, 2, 3, 4, 5] +iterator = iter(numbers) + +# 手动获取元素 +print(next(iterator)) # 1 +print(next(iterator)) # 2 +print(next(iterator)) # 3 +print(next(iterator)) # 4 +print(next(iterator)) # 5 +# print(next(iterator)) # 抛出 StopIteration 异常 + +# 使用默认值避免异常 +iterator2 = iter([1, 2]) +print(next(iterator2)) # 1 +print(next(iterator2)) # 2 +print(next(iterator2, "没有更多元素")) # 没有更多元素 +# 使用场景: + +# 需要精确控制迭代过程 +# 处理大型数据集时避免一次性加载 +# 实现自定义的迭代逻辑 + +# enumerate() - 带索引的迭代 +# enumerate() 函数在遍历可迭代对象时同时提供索引和值,是处理需要索引的场景的最佳选择。 +# 语法 +# enumerate(iterable, start=0) +# 参数: +# iterable:要遍历的可迭代对象 +# start:索引起始值,默认为 0 +# 返回值:返回 (索引, 元素) 元组的迭代器 +# 基本用法 +colors = ["red", "green", "blue"] +for idx, color in enumerate(colors): + print(f"{idx}: {color}") +# 输出: +# 0: red +# 1: green +# 2: blue + +# 自定义起始索引 +for idx, color in enumerate(colors, start=1): + print(f"第{idx}个颜色: {color}") +# 输出: +# 第1个颜色: red +# 第2个颜色: green +# 第3个颜色: blue +# 常见应用场景: + +# 需要同时访问索引和值的循环 +# 创建带编号的输出 +# 在循环中修改列表元素 +# 生成带索引的数据结构 + +# zip() - 并行迭代 +# zip() 函数将多个可迭代对象"并行"组合,每次迭代返回一个包含各对象对应元素的元组。 +# 语法: +# zip(iter1, iter2, ..., iterN) +# 特点: +# 返回迭代器,惰性求值 +# 以最短的可迭代对象长度为准 +# 支持任意数量的可迭代对象 +names = ["Alice", "Bob", "Charlie"] +ages = [25, 30, 35] +cities = ["北京", "上海", "广州"] +for name, age, city in zip(names, ages, cities): + print(f"{name},{age}岁,来自{city}") + +# 长度不同: +# 以最短的为准 +list1 = [1, 2, 3, 4] +list2 = ["a", "b"] +for num, letter in zip(list1, list2): + print(f"{num}: {letter}") +# 输出: +# 1: a +# 2: b +# 高级用法: + +# 数据转置 +# 行转列 +scores = [ + (85, 92, 78), # 张三的成绩 + (76, 88, 95), # 李四的成绩 + (90, 85, 92), # 王五的成绩 +] +chinese, math, english = zip(*scores) +print("语文成绩:", chinese) # (85, 76, 90) +print("数学成绩:", math) # (92, 88, 85) +print("英语成绩:", english) # (78, 95, 92) + +# 与推导式结合: +# 计算对应位置元素的和 +list1 = [1, 2, 3] +list2 = [4, 5, 6] +result = [x + y for x, y in zip(list1, list2)] +print(result) # [5, 7, 9] + +# 处理不同长度的序列: +from itertools import zip_longest + +# 保留所有元素,用默认值填充 +a = [1, 2, 3] +b = [4, 5] +for x, y in zip_longest(a, b, fillvalue=0): + print(f"{x} + {y} = {x + y}") +# 输出: +# 1 + 4 = 5 +# 2 + 5 = 7 +# 3 + 0 = 3 + + +# map() - 映射迭代 +# map() 函数对可迭代对象的每个元素应用指定函数,返回一个迭代器。 + +# 语法: +# map(function, iterable, ...) +# 参数: +# function:要应用的函数(可以是内置函数、lambda 或自定义函数) +# iterable:一个或多个可迭代对象 +# 特点: +# 返回惰性迭代器,需要显式消费 +# 支持多个可迭代对象,以最短的为准 +# 适合批量数据转换 +# 基本用法 +numbers = [1, 2, 3, 4] +squared = map(lambda x: x**2, numbers) +print(list(squared)) # [1, 4, 9, 16] + +# 类型转换 +nums = [10, 20, 30] +str_list = map(str, nums) +print(list(str_list)) # ['10', '20', '30'] + +# 多序列处理 +list1 = [1, 2, 3] +list2 = [4, 5, 6, 7] +result = map(lambda x, y: x + y, list1, list2) +print(list(result)) # [5, 7, 9] + + +# 自定义函数 +def double(x): + return x * 2 + + +numbers = [5, 6, 7] +doubled = map(double, numbers) +print(list(doubled)) # [10, 12, 14] + +# 优势: +# 代码简洁,函数式编程风格 +# 惰性求值,内存效率高 +# 易于与其他迭代器函数组合 + + +# filter() - 过滤迭代 +# filter() 函数根据指定条件过滤可迭代对象中的元素,只保留满足条件的元素。 + +# 语法: +# filter(function, iterable) +# 参数: + +# function:判断函数,返回 True/False。如果为 None,则使用元素自身的布尔值 +# iterable:要过滤的可迭代对象 +# 特点: + +# 返回惰性迭代器,需要显式消费 +# 只保留使函数返回 True 的元素 +# 适合数据清洗和条件筛选 +# 基本用法 +numbers = [1, 2, 3, 4, 5, 6] +even_numbers = filter(lambda x: x % 2 == 0, numbers) +print(list(even_numbers)) # [2, 4, 6] + +# 过滤假值 +data = ["hello", "", "python", None, " ", "AI"] +valid_data = filter(None, data) +print(list(valid_data)) # ['hello', 'python', ' ', 'AI'] + + +# 自定义过滤函数 +def is_positive(x): + return x > 0 + + +numbers = [0, -1, 2, -3, 4] +positive = filter(is_positive, numbers) +print(list(positive)) # [2, 4] + + +# 复杂条件 +def is_valid_email(email): + return email and "@" in email and "." in email + + +emails = ["user@example.com", "invalid", "test@domain.org", ""] +valid_emails = filter(is_valid_email, emails) +print(list(valid_emails)) # ['user@example.com', 'test@domain.org'] + +# 应用场景: +# 数据清洗和验证 +# 条件筛选 +# 去除无效数据 +# 与 map() 等函数组合使用 + + +# 迭代器链式操作 +# 链式操作将多个迭代器函数串联起来,形成数据处理流水线,具有惰性求值优势。 + +# 1.常见链式操作函数 +# filter(func, iterable):过滤满足条件的元素 +# map(func, iterable):对每个元素应用函数 +# itertools.islice(iterable, n):取前n个元素 +import itertools + + +def process_data_pipeline(data): + """数据处理流水线""" + # 1. 过滤正数 + filtered = filter(lambda x: x > 0, data) + # 2. 计算平方 + squared = map(lambda x: x**2, filtered) + # 3. 取前5个 + limited = itertools.islice(squared, 5) + return limited + + +# 示例数据 +data = [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6] +result = process_data_pipeline(data) +print(list(result)) # [1, 4, 9, 16, 25] + +# 更简洁的写法 +result = itertools.islice(map(lambda x: x**2, filter(lambda x: x > 0, data)), 5) +print(list(result)) # [1, 4, 9, 16, 25] + +# 优势: + +# 内存效率:按需处理,不一次性加载所有数据 +# 性能优化:只为需要的数据执行运算 +# 代码简洁:易于组合复杂的数据处理逻辑 +# 可读性强:流水线式的处理流程清晰明了 +# 应用场景: + +# 数据清洗和预处理 +# 日志文件分析 +# 流式数据处理 +# 大数据集处理 + + +# 迭代器工具函数 +# 1.itertools 常用函数 +# itertools 模块提供了丰富的迭代器构造工具,支持流式数据处理: + +# chain(*iterables):连接多个可迭代对象 +# compress(data, selectors):根据布尔掩码选择元素 +# dropwhile(predicate, iterable):丢弃开头满足条件的元素 +# takewhile(predicate, iterable):获取开头满足条件的元素 +# groupby(iterable, key=None):按key分组(需要先排序) +import itertools + +# chain - 连接多个迭代器 +chain_iter = itertools.chain([1, 2], [3, 4], [5, 6]) +print("Chain:", list(chain_iter)) # [1, 2, 3, 4, 5, 6] + +# compress - 条件过滤 +data = ["A", "B", "C", "D"] +selectors = [1, 0, 1, 0] +compress_iter = itertools.compress(data, selectors) +print("Compress:", list(compress_iter)) # ['A', 'C'] + +# dropwhile - 丢弃开头满足条件的元素 +drop_iter = itertools.dropwhile(lambda x: x < 5, [1, 2, 3, 4, 5, 6, 1, 2]) +print("Dropwhile:", list(drop_iter)) # [5, 6, 1, 2] + +# takewhile - 获取开头满足条件的元素 +take_iter = itertools.takewhile(lambda x: x < 5, [1, 2, 3, 4, 5, 6, 1, 2]) +print("Takewhile:", list(take_iter)) # [1, 2, 3, 4] + +# groupby - 分组(需要先排序) +data = ["apple", "animal", "banana", "bird", "cherry", "cat"] +sorted_data = sorted(data, key=lambda x: x[0]) # 按首字母排序 +grouped = itertools.groupby(sorted_data, key=lambda x: x[0]) +for key, group in grouped: + print(f"{key}: {list(group)}") +# 输出: +# a: ['animal', 'apple'] +# b: ['banana', 'bird'] +# c: ['cat', 'cherry'] + +# 优势: + +# 惰性求值,内存效率高 +# 函数式编程风格 +# 易于组合复杂的数据处理逻辑 +# 适合处理大数据集 + + +# 迭代器性能优势 +# 内存效率: + +# 列表:一次性创建所有元素,占用大量内存 +# 迭代器:按需生成元素,内存占用极小 +# 处理速度: + +# 列表:需要预先计算所有元素 +# 迭代器:惰性求值,只计算需要的元素 +# 适用场景: + +# 大数据集处理 +# 无限数据流 +# 内存受限环境 +# 流式数据处理 diff --git a/20-24/05shengchengqi.py b/20-24/05shengchengqi.py new file mode 100644 index 0000000..cc2ef3b --- /dev/null +++ b/20-24/05shengchengqi.py @@ -0,0 +1,341 @@ +# 生成器是 Python 中一种特殊的迭代器,使用 yield 关键字创建,具有惰性计算特性。 + +# 1.1.什么是生成器? +# 生成器是一种特殊的函数,具有以下特征: + +# 惰性计算:按需生成值,不立即计算所有结果 +# 内存高效:一次只处理一个值,不存储整个序列 +# 可迭代:可以用在 for 循环中 +# 状态保持:记住上次执行的位置 +# 协程特性:支持双向通信,可以接收外部数据 + +# 创建生成器的方法 +# 生成器有两种主要创建方式: + +# 生成器函数:使用 yield 关键字的函数 +# 生成器表达式:类似列表推导式的语法,但使用圆括号 +# 生成器函数 vs 普通函数 +# 特性 普通函数 生成器函数 +# 返回值 使用 return 使用 yield +# 执行方式 一次性执行完毕 可以暂停和恢复 +# 内存使用 一次性创建所有结果 按需生成,节省内存 +# 状态保持 不保持状态 保持执行状态 + +# 优势: +# 内存效率高,适合处理大数据集 +# 支持复杂的控制流 +# 可以实现协程模式 +# 代码更简洁易读 + +# 方法1:生成器函数 +# 生成器函数使用 yield 关键字创建,每次遇到 yield 会暂停执行并返回值。 + +# 语法特点: + + +# 使用 def 关键字定义 +# 函数体内必须包含 yield 语句 +# 调用时返回生成器对象,不立即执行 +# 通过 next() 或 for 循环驱动执行 +def my_generator(): + """简单的生成器函数示例""" + print("第一步") + yield "A" + print("第二步") + yield "B" + print("第三步") + yield "C" + + +# 创建生成器对象 +gen = my_generator() + +# 逐步获取值 +print(next(gen)) # 输出: 第一步 \n A +print(next(gen)) # 输出: 第二步 \n B +print(next(gen)) # 输出: 第三步 \n C +# print(next(gen)) # 抛出 StopIteration 异常 + +# 使用 for 循环遍历 +for value in my_generator(): + print(f"获取到: {value}") +# 重要特性: + +# 生成器只能遍历一次,用完即耗尽 +# 每次 yield 会保存函数状态 +# 适合处理大量数据或复杂逻辑 +# 支持协程模式(双向通信) + + +# 方法2:生成器表达式 +# 生成器表达式是创建生成器最简洁的方式,语法类似列表推导式,但使用圆括号。 + +# 基本语法: +# (expression for item in iterable [if condition]) +# 创建平方数生成器 +gen = (x**2 for x in range(5)) + +print(type(gen)) # +print(next(gen)) # 0 +print(next(gen)) # 1 +print(next(gen)) # 4 +print(next(gen)) # 9 +print(next(gen)) # 16 +# print(next(gen)) # StopIteration + +# 使用 for 循环遍历 +for value in (x * 3 for x in range(4)): + print(value, end=" ") # 输出: 0 3 6 9 + +# 带条件的生成器表达式 +even_squares = (x**2 for x in range(10) if x % 2 == 0) +print(list(even_squares)) # [0, 4, 16, 36, 64] + +# 优势: + +# 语法简洁,一行代码创建生成器 +# 内存效率高,惰性求值 +# 适合简单的数据转换和过滤 +# 可以与其他函数链式组合 +# 适用场景: + +# 简单的数据转换 +# 一次性遍历 +# 内存敏感的场景 +# 与内置函数配合使用 + +# 列表推导式 vs 生成器表达式 +# numbers = [1, 2, 3, 4, 5] + +# # 列表推导式 - 立即计算所有结果 +# squares_list = [x**2 for x in numbers] +# print(squares_list) # [1, 4, 9, 16, 25] +# print(type(squares_list)) # + +# # 生成器表达式 - 惰性计算 +# squares_gen = (x**2 for x in numbers) +# print(squares_gen) # at 0x...> +# print(type(squares_gen)) # + +# # 遍历生成器 +# for square in squares_gen: +# print(square, end=" ") # 1 4 9 16 25 + +# 特性 列表推导式 生成器表达式 +# 语法 [expr for item in iterable] (expr for item in iterable) +# 内存使用 一次性创建所有元素 按需生成,节省内存 +# 执行时机 立即执行 惰性求值 +# 可重复使用 是 否(只能遍历一次) +# 适用场景 需要多次访问结果 一次性遍历,大数据集 + + +# 生成器方法 +# 生成器提供了几个特殊方法,支持更高级的交互和控制。 + +# 4.1.send() 方法 - 向生成器发送值 +# send() 方法可以向生成器发送值,实现双向通信。 + + +# 使用规则: +# 首次启动生成器必须使用 next() +# 只有生成器暂停在 yield 后才能使用 send() +# send() 会返回生成器产生的下一个值 +def simple_echo(): + """简单的回声生成器""" + received = yield "请给我一个值" + yield f"你发来的是:{received}" + + +gen = simple_echo() +print(next(gen)) # 输出: 请给我一个值 +print(gen.send("Hello")) # 输出: 你发来的是:Hello + +# 执行流程: + +# next(gen) 启动生成器,执行到第一个 yield +# gen.send("Hello") 将值发送给生成器,继续执行 +# 生成器接收值并处理,产生下一个结果 +# 应用场景: + +# 协程编程 +# 状态机实现 +# 数据管道处理 +# 与外部系统交互 + +# throw() 方法 - 向生成器抛出异常 +# throw() 方法可以在生成器暂停处抛出异常,实现异常处理机制。 + +# 使用场景: + + +# 外部主动通知生成器发生错误 +# 优雅地中断生成器执行 +# 实现异常处理和恢复逻辑 +def exception_generator(): + """演示异常处理的生成器""" + try: + yield "开始" + yield "继续" + yield "结束" + except ValueError as e: + yield f"捕获异常: {e}" + yield "恢复执行" + + +# 使用示例 +gen = exception_generator() +print(next(gen)) # 开始 +print(next(gen)) # 继续 +print(gen.throw(ValueError("测试异常"))) # 捕获异常: 测试异常 +print(next(gen)) # 恢复执行 +# 异常处理流程: + +# 生成器正常执行到 yield 语句 +# 外部调用 throw() 抛出异常 +# 生成器内部捕获异常并处理 +# 可以选择恢复执行或终止生成器 +# 注意事项: + +# 如果异常未被捕获,会向外传播 +# 异常处理完成后,生成器可以继续执行 +# 适合实现错误恢复和资源清理 + + +# close() 方法 - 关闭生成器 +# close() 方法用于主动终止生成器,触发资源清理。 + + +# 使用场景: +# 读取大文件时提前终止 +# 数据库连接管理 +# 网络连接清理 +# 资源释放 +def closable_generator(): + """可关闭的生成器示例""" + try: + yield "第一步" + yield "第二步" + yield "第三步" + except GeneratorExit: + print("生成器被关闭,正在清理资源") + raise # 必须重新抛出异常 + + +# 使用示例 +gen = closable_generator() +print(next(gen)) # 第一步 +gen.close() # 生成器被关闭,正在清理资源 +# 后续调用 next(gen) 会抛出 StopIteration +# 关闭流程: + +# 调用 close() 方法 +# 生成器在 yield 处抛出 GeneratorExit 异常 +# 生成器内部捕获异常并清理资源 +# 必须重新抛出异常,否则会触发 RuntimeError +# 注意事项: + +# 只能在生成器暂停时关闭 +# 关闭后再次调用 next() 会抛出 StopIteration +# 适合实现资源管理和清理逻辑 + + +# 高级生成器模式 +# 6.1.生成器委托 (yield from) +# yield from 语句可以简化生成器委托,让代码更简洁。 + + +# 基本语法: +# yield from iterable +# 原始写法 +def chain_generators_old(*iterables): + for iterable in iterables: + for item in iterable: + yield item + + +# 使用 yield from +def chain_generators(*iterables): + for iterable in iterables: + yield from iterable + + +# 使用示例 +gen1 = (x for x in range(3)) +gen2 = (x for x in range(3, 6)) +gen3 = (x for x in range(6, 9)) + +chained = chain_generators(gen1, gen2, gen3) +print(list(chained)) # [0, 1, 2, 3, 4, 5, 6, 7, 8] +# 优势: + +# 代码更简洁,无需嵌套循环 +# 自动处理子生成器的返回值 +# 支持协程通信 +# 适合递归遍历树形结构 +# 应用场景: + +# 拼接多个生成器 +# 递归遍历树形结构 +# 协程通信 +# 管道式编程 + + +# 协程模式 +# 协程是生成器的重要扩展,支持双向通信和协作式编程。 + +# 协程特点: + + +# 使用 yield 暂停和恢复执行 +# 支持双向数据交换 +# 可以接收外部发送的数据 +# 适合异步任务调度 +def average_coroutine(): + """协程模式:实时计算平均值""" + total = 0 + count = 0 + average = 0 + + while True: + value = yield average # 接收外部数据 + if value is None: + break + total += value + count += 1 + average = total / count + + return average + + +# 使用协程 +coro = average_coroutine() +next(coro) # 预激协程 +print(coro.send(10)) # 10.0 +print(coro.send(20)) # 15.0 +print(coro.send(30)) # 20.0 + +try: + coro.send(None) # 终止协程 +except StopIteration as e: + print("最终平均值:", e.value) # 最终平均值: 20.0 + +# 协程优势: + +# 支持双向通信 +# 可以暂停和恢复执行 +# 适合异步编程 +# 代码结构清晰 +# 应用场景: + +# 异步任务调度 +# 流式数据处理 +# 事件驱动编程 +# 状态机实现 + +# 生成器与迭代器 +# 7.1.关系说明 +# 生成器是 Python 中实现迭代器协议的一种简便方式: + +# 生成器本身就是特殊的迭代器,实现了 __iter__() 和 __next__() 方法 +# 所有生成器都能用于 for 循环,与其他迭代器无缝兼容 +# 生成器提供了更简洁的迭代器实现方式 diff --git a/20-24/06file.py b/20-24/06file.py new file mode 100644 index 0000000..f934d25 --- /dev/null +++ b/20-24/06file.py @@ -0,0 +1,411 @@ +# 概述 +# Python 提供了丰富的内置函数和方法来处理文件,支持文本文件、二进制文件、CSV、JSON 等多种格式的读写操作。掌握文件操作是 Python 编程的重要技能。 + +# 2.核心概念 +# 文件对象:通过 open() 函数创建,用于文件读写操作 +# 文件模式:指定文件的打开方式(读取、写入、追加等) +# 编码:处理文本文件时指定字符编码,避免乱码 +# 上下文管理:使用 with 语句自动管理文件资源 + +# 打开文件 +# 3.1.基本语法 +# 使用 open() 函数打开文件,返回文件对象用于后续操作: +# file = open(file, mode='r', encoding=None) +# 参数说明: +# file:文件路径(字符串),可以是相对路径或绝对路径 +# mode:打开模式(字符串),默认为 'r'(只读) +# encoding:字符编码(字符串),文本文件推荐使用 'utf-8' +# 模式 描述 说明 +# 'r' 只读(默认) 文件必须存在,否则报错 +# 'w' 写入 覆盖已有文件,不存在则创建 +# 'a' 追加 在文件末尾添加内容,不存在则创建 +# 'x' 创建 创建新文件,已存在则失败 +# 'b' 二进制 与上述模式组合使用(如 'rb', 'wb') +# 't' 文本(默认) 文本模式,处理字符串 +# '+' 读写 与上述模式组合使用(如 'r+', 'w+') +# 只读模式打开文本文件 +file = open("data.txt", "r", encoding="utf-8") + +# 写入模式打开文件 +file = open("output.txt", "w", encoding="utf-8") + +# 二进制模式打开文件 +file = open("image.png", "rb") + +# 4.重要注意事项 +# 文件关闭:操作完成后必须关闭文件,避免资源泄露 +# 编码指定:处理中文等非ASCII字符时务必指定编码 +# 异常处理:文件不存在或权限不足时会抛出异常 +# 推荐使用 with 语句:自动管理文件资源,更安全可靠 + +# 4.读取文件内容 +# 4.1.读取方法概述 +# Python 提供了多种读取文件内容的方法: +# 方法 描述 适用场景 +# read() 读取整个文件 小文件,需要完整内容 +# readline() 读取一行 逐行处理,大文件 +# readlines() 读取所有行到列表 需要随机访问行 +# for line in file 遍历文件对象 推荐方式,简洁高效 +# 重要注意事项 +# 使用 with 语句:自动管理文件资源,避免泄露 +# 大文件处理:建议逐行读取,避免内存溢出 +# 编码指定:处理中文时务必指定 encoding='utf-8' +# 异常处理:文件不存在或权限不足时会抛出异常 + +# 读取整个文件 +# 读取整个文件内容 +with open("example.txt", "r", encoding="utf-8") as file: + content = file.read() + print(content) +# 适用场景: + +# 文件较小,可以一次性加载到内存 +# 需要完整的文件内容进行处理 +# 配置文件、小文本文件等 + +# 逐行读取 +# 逐行读取适合处理大文件或需要按行处理内容的场景 + +# 方法1:使用 readline() +# 使用 readline() 逐行读取 +# with open("example.txt", "r", encoding="utf-8") as file: +# line = file.readline() +# while line: +# print(line.strip()) +# line = file.readline() + +# 方法2:使用 readlines() +# 使用 readlines() 读取所有行 +with open("example.txt", "r", encoding="utf-8") as file: + lines = file.readlines() + for line in lines: + print(line.strip()) + +# 方法3:直接遍历文件对象(推荐) +# 直接遍历文件对象(推荐方式) +# with open("example.txt", "r", encoding="utf-8") as file: +# for line in file: +# print(line.strip()) +# 方法对比: + +# 方法 优点 缺点 适用场景 +# readline() 内存效率高 代码较复杂 大文件逐行处理 +# readlines() 代码简洁 内存占用大 小文件,需要随机访问 +# for line in file 代码最简洁,效率高 - 推荐使用 + +# 读取指定字节数 +# 使用 read(size) 方法可以读取指定数量的字符或字节。 +# 基本用法 +# 读取前100个字符 +with open("example.txt", "r", encoding="utf-8") as file: + chunk = file.read(100) + print(chunk) +# 分块读取大文件 +# 分块读取大文件 +with open("large_file.txt", "r", encoding="utf-8") as file: + while True: + chunk = file.read(1000) # 每次读取1000个字符 + if not chunk: # 读取结束 + break + print(chunk) +# 二进制文件读取 +# 读取二进制文件 +with open("image.jpg", "rb") as file: + chunk = file.read(1024) # 读取1024字节 + print(chunk) +# 重要说明: +# 文本模式:size 参数表示字符数 +# 二进制模式:size 参数表示字节数 +# 适合处理大文件,避免内存溢出 +# 结合循环可以实现流式处理 + + +# 写入文件 +# 方法 描述 特点 +# write() 写入字符串 不自动换行,需要手动添加 \n +# writelines() 写入字符串序列 不自动换行,需要序列中自带 \n +# 写入模式 +# 覆盖写入('w'):清空原内容,重新写入 +# 追加写入('a'):在文件末尾添加内容 +# 创建写入('x'):创建新文件,已存在则失败 +# 5.3.重要注意事项 +# 使用 with 语句:自动管理文件资源,避免数据丢失 +# 编码指定:处理中文时务必指定 encoding='utf-8' +# 换行符:写入方法不会自动添加换行符,需要手动添加 +# 异常处理:权限不足或磁盘空间不够时会抛出异常 + +# 写入字符串 +# 单独写入字符串 +# 覆盖写入模式 +with open("output.txt", "w", encoding="utf-8") as file: + file.write("Hello, World!\n") + file.write("This is a new line.\n") + +# 追加写入模式 +with open("output.txt", "a", encoding="utf-8") as file: + file.write("This line is appended.\n") + +# 批量写入字符串 +# 准备要写入的字符串列表 +lines = ["Line 1\n", "Line 2\n", "Line 3\n"] + +# 使用 writelines() 批量写入 +with open("output.txt", "w", encoding="utf-8") as file: + file.writelines(lines) + +# 或者使用循环写入 +with open("output.txt", "w", encoding="utf-8") as file: + for line in lines: + file.write(line) + +# 写入要点: +# 写入方法不会自动添加换行符 +# 需要手动在字符串末尾添加 \n +# 使用 with 语句确保文件正确关闭 +# 指定编码避免中文乱码 + + +# 使用 with 语句(推荐) +# 基本用法 +# with 语句是 Python 推荐的文件操作方式,可以自动管理文件资源: +# 使用 with 语句自动管理文件资源 +with open("example.txt", "r", encoding="utf-8") as file: + content = file.read() + print(content) +# 文件会自动关闭,无需手动调用 file.close() +# 优势 +# 自动关闭:无论是否发生异常,文件都会被正确关闭 +# 代码简洁:无需手动管理文件资源 +# 异常安全:即使发生异常也能确保资源释放 +# 推荐使用:Python 官方推荐的文件操作方式 + +# 对比传统方式 +# 传统方式(不推荐) +file = open("example.txt", "r", encoding="utf-8") +try: + content = file.read() + print(content) +finally: + file.close() # 必须手动关闭 + +# with 语句(推荐) +with open("example.txt", "r", encoding="utf-8") as file: + content = file.read() + print(content) +# 自动关闭,更简洁安全 + +# 文件位置操作 +# 获取当前位置 +# 使用 tell() 方法获取文件指针的当前位置: +with open("example.txt", "r", encoding="utf-8") as file: + print(f"初始位置: {file.tell()}") # 0 + content = file.read(5) + print(f"读取后位置: {file.tell()}") # 5 + +# 移动文件指针 +# 使用 seek() 方法移动文件指针到指定位置: +with open("example.txt", "rb") as file: + # 移动到文件开头 + file.seek(0) + print(f"位置: {file.tell()}") # 0 + + # 移动到第10个字节 + file.seek(10) + print(f"位置: {file.tell()}") # 10 + + # 从当前位置向后移动5个字节 + file.seek(5, 1) + print(f"位置: {file.tell()}") # 15 + + # 从文件末尾向前移动10个字节 + file.seek(-10, 2) + print(f"位置: {file.tell()}") # 文件大小-10 + +# seek() 参数说明 +# offset:偏移量(字节为单位) +# whence:相对位置 +# 0:从文件开头计算(默认) +# 1:从当前位置计算 +# 2:从文件末尾计算 + +# 重要注意事项 +# 文本模式:seek() 行为可能受编码影响,建议使用二进制模式 +# 二进制模式:seek() 行为更可预测,适合精确定位 +# 应用场景:断点续传、日志处理、大文件分块处理 + +# 文件属性检查 +# 基本属性检查 +# 使用 os.path 模块检查文件的基本属性: +import os + +# 检查文件是否存在 +if os.path.exists("demo.txt"): + print("文件存在") +else: + print("文件不存在") + +# 判断是文件还是目录 +if os.path.isfile("demo.txt"): + print("是文件") +if os.path.isdir("test_folder"): + print("是目录") + +# 获取文件大小 +size = os.path.getsize("demo.txt") +print(f"文件大小: {size} 字节") + +# 详细属性信息 +# 使用 os.stat() 获取文件的详细信息: +import os +from datetime import datetime + +# 获取文件详细信息 +info = os.stat("demo.txt") + +print(f"文件大小: {info.st_size} 字节") +print(f"创建时间: {datetime.fromtimestamp(info.st_ctime)}") +print(f"最后访问: {datetime.fromtimestamp(info.st_atime)}") +print(f"最后修改: {datetime.fromtimestamp(info.st_mtime)}") +print(f"文件权限: {oct(info.st_mode)}") + + +# 常用属性检查方法 +# 方法 描述 返回值 +# os.path.exists() 检查路径是否存在 True/False +# os.path.isfile() 检查是否为文件 True/False +# os.path.isdir() 检查是否为目录 True/False +# os.path.getsize() 获取文件大小 字节数 +# os.stat() 获取详细信息 stat_result 对象 + + +# 完整实例 +# 1. 创建并写入文件 +with open("demo.txt", "w", encoding="utf-8") as file: + file.write("这是第一行\n") + file.write("这是第二行\n") + file.write("这是第三行\n") + +# 2. 读取并显示文件内容 +print("文件内容:") +with open("demo.txt", "r", encoding="utf-8") as file: + for line_num, line in enumerate(file, 1): + print(f"第{line_num}行: {line.strip()}") + +# 3. 追加内容到文件 +with open("demo.txt", "a", encoding="utf-8") as file: + file.write("这是追加的内容\n") + +# 4. 显示追加后的内容 +print("\n追加后的内容:") +with open("demo.txt", "r", encoding="utf-8") as file: + print(file.read()) + + +# 处理不同类型的文件 +# CSV 文件 +# CSV(逗号分隔值)文件是常见的表格数据格式,适合数据交换和存储。 +# CSV 文件格式示例 +# 姓名, 年龄, 城市 +# 张三, 25, 北京 +# 李四, 30, 上海 + +# 读写 CSV 文件 +# import csv + +# # 写入 CSV 文件 +# with open("data.csv", "w", newline="", encoding="utf-8") as file: +# writer = csv.writer(file) +# writer.writerow(["姓名", "年龄", "城市"]) # 写入表头 +# writer.writerow(["张三", "25", "北京"]) # 写入数据 +# writer.writerow(["李四", "30", "上海"]) + +# # 读取 CSV 文件 +# with open("data.csv", "r", newline="", encoding="utf-8") as file: +# reader = csv.reader(file) +# for row in reader: +# print(row) +# CSV 文件特点 +# 格式简单:逗号分隔字段,换行分隔记录 +# 兼容性好:Excel、数据库等广泛支持 +# 易于处理:Python csv 模块提供便捷操作 +# 注意编码:处理中文时务必指定 utf-8 编码 + +# SON 文件 +# JSON(JavaScript 对象表示法)是轻量级的数据交换格式,广泛用于数据存储和传输。 +# JSON 文件特点 +# 格式简洁:易于阅读和编写 +# 跨平台:支持多种编程语言 +# 结构化:支持复杂的数据结构 +# 广泛应用:网络通信、配置文件等 +# 读取JSON文件 +import json + +# 准备数据 +data = {"name": "张三", "age": 25, "cities": ["北京", "上海", "广州"]} + +# 写入 JSON 文件 +with open("data.json", "w", encoding="utf-8") as file: + json.dump(data, file, ensure_ascii=False, indent=4) + +# 读取 JSON 文件 +with open("data.json", "r", encoding="utf-8") as file: + loaded_data = json.load(file) + print(loaded_data) +# JSON 文件优势 +# 数据完整性:保持 Python 对象的完整结构 +# 可读性强:格式化后易于阅读和调试 +# 兼容性好:与 Web API 和数据库无缝对接 +# 类型安全:自动处理数据类型转换 + +# 错误处理 +# 11.1.常见文件操作异常 +# 文件操作中可能遇到的各种异常 +# 异常类型 描述 常见原因 +# FileNotFoundError 文件不存在 路径错误、文件被删除 +# PermissionError 权限不足 文件被占用、无写入权限 +# IOError 输入输出错误 磁盘空间不足、设备错误 +# UnicodeDecodeError 编码错误 文件编码与指定编码不匹配 + +# 异常处理示例 +try: + with open("nonexistent.txt", "r", encoding="utf-8") as file: + content = file.read() + print(content) +except FileNotFoundError: + print("文件不存在!") +except PermissionError: + print("权限不足,无法访问文件!") +except IOError as e: + print(f"文件操作错误: {e}") +except UnicodeDecodeError: + print("文件编码错误!") +finally: + print("文件操作完成") + + +# 错误处理最佳实践 +# 具体异常:捕获具体的异常类型,避免使用过于宽泛的 except +# 异常信息:提供有意义的错误信息,便于调试 +# 资源清理:使用 with 语句自动管理资源 +# 日志记录:记录异常信息,便于问题排查 +# 用户友好:向用户提供清晰的错误提示 + +# 12.最佳实践 +# 12.1.文件操作原则 +# 使用 with 语句:自动管理文件资源,确保正确关闭 +# 指定编码:处理中文等非ASCII字符时务必指定 utf-8 +# 异常处理:捕获并处理文件操作异常,提高程序健壮性 +# 选择合适模式:根据需求选择读取、写入或追加模式 +# 考虑文件大小:大文件使用分块读取,避免内存溢出 + +# 12.2.性能优化建议 +# 大文件处理:使用生成器或分块读取 +# 批量操作:使用 writelines() 批量写入 +# 内存管理:及时释放不需要的文件对象 +# 缓存策略:合理使用文件缓存提高性能 + +# 12.3.安全注意事项 +# 路径验证:检查文件路径的有效性 +# 权限检查:确保有足够的文件操作权限 +# 资源清理:使用 with 语句确保资源释放 +# 异常处理:妥善处理各种异常情况 diff --git a/20-24/07file-path.py b/20-24/07file-path.py new file mode 100644 index 0000000..6ab9e7d --- /dev/null +++ b/20-24/07file-path.py @@ -0,0 +1,407 @@ +# Python 提供了强大的文件路径操作功能,主要使用 os.path 模块和 pathlib 模块。掌握路径操作对于文件管理、数据处理和跨平台开发至关重要。 +# 核心概念 +# 路径:指向文件或目录的字符串或对象 +# 绝对路径:从根目录开始的完整路径 +# 相对路径:相对于当前工作目录的路径 +# 跨平台:不同操作系统使用不同的路径分隔符 + +# 导入必要模块 +import os # 操作系统接口 +import os.path # 传统路径操作 +from pathlib import Path # 现代路径操作(推荐) +import glob # 文件通配符搜索 +import shutil # 高级文件操作 + +# os.path 模块 - 传统路径操作 +# 路径拼接和分解 +# 路径拼接 +# 使用 os.path.join() 自动处理不同操作系统的路径分隔符: +import os + +# 路径拼接 - 自动处理分隔符 +full_path = os.path.join("父文件夹", "子文件夹", "文件.txt") +print(full_path) # Linux/Mac: 父文件夹/子文件夹/文件.txt +# Windows: 父文件夹\子文件夹\文件.txt + +# 获取文件名和目录名 +import os + +path = "/home/user/documents/file.txt" + +# 获取文件名 +print(os.path.basename(path)) # file.txt + +# 获取目录名 +print(os.path.dirname(path)) # /home/user/documents + +# 分割路径 +print(os.path.split(path)) # ('/home/user/documents', 'file.txt') + +# 分离扩展名 +import os + +# 分离文件名和扩展名 +name, ext = os.path.splitext("example.tar.gz") +print(name) # example.tar +print(ext) # .gz + +# 获取绝对路径 +import os + +# 获取绝对路径 +print(os.path.abspath("file.txt")) # 不解析符号链接 +print(os.path.realpath("file.txt")) # 解析符号链接 + +# 路径检查和属性 +# 函数 描述 返回值 +# os.path.exists() 检查路径是否存在 True/False +# os.path.isfile() 检查是否为文件 True/False +# os.path.isdir() 检查是否为目录 True/False +# os.path.islink() 检查是否为符号链接 True/False +# os.path.getsize() 获取文件大小 字节数 +# os.path.getmtime() 获取最后修改时间 时间戳 +# os.path.getatime() 获取最后访问时间 时间戳 + +import os + +path = "/home/user/documents" + +# 检查路径属性 +print(os.path.exists(path)) # True/False +print(os.path.isfile(path)) # True/False +print(os.path.isdir(path)) # True/False +print(os.path.islink(path)) # True/False + +# 获取文件信息 +if os.path.isfile(path): + print(f"文件大小: {os.path.getsize(path)} 字节") + print(f"修改时间: {os.path.getmtime(path)}") + + +# pathlib 模块 - 现代路径操作(推荐) +# pathlib 是 Python 3.4+ 引入的现代路径操作模块,提供面向对象的接口,更加直观和易用。 + +# 创建路径对象 +from pathlib import Path + +# 创建路径对象 +path1 = Path("/home/user/documents") # 绝对路径 +path2 = Path("relative/path") # 相对路径 +path3 = Path.cwd() # 当前工作目录 +path4 = Path.home() # 用户主目录 + +print(f"绝对路径: {path1}") +print(f"当前目录: {path3}") +print(f"用户主目录: {path4}") + +# 路径对象优势 +# 面向对象:更直观的 API 设计 +# 跨平台:自动处理路径分隔符 +# 链式操作:支持方法链式调用 +# 类型安全:更好的类型提示支持 + +# 路径属性和方法 +# 基本属性 +from pathlib import Path + +p = Path("/home/user/example/file.txt") + +# 路径组成部分 +print(f"完整路径: {p}") # /home/user/example/file.txt +print(f"文件名: {p.name}") # file.txt +print(f"文件名(无后缀): {p.stem}") # file +print(f"扩展名: {p.suffix}") # .txt +print(f"父路径: {p.parent}") # /home/user/example +print(f"磁盘/锚: {p.anchor}") # Linux: /, Windows: C:\ + +# 路径修改 +# 路径修改方法 +print(f"替换文件名: {p.with_name('data.csv')}") # /home/user/example/data.csv +print(f"替换扩展名: {p.with_suffix('.md')}") # /home/user/example/file.md + +# 路径检查 +# 基本检查 +print(f"是否存在: {p.exists()}") +print(f"是否为文件: {p.is_file()}") +print(f"是否为目录: {p.is_dir()}") +print(f"是否为绝对路径: {p.is_absolute()}") +print(f"绝对路径: {p.resolve()}") + +# 安全获取文件信息 +# 安全地获取文件信息 +if p.is_file(): + stat = p.stat() + print(f"文件大小: {stat.st_size} 字节") + print(f"最后修改: {stat.st_mtime}") +else: + print("不是文件,无法获取大小和时间") + + +# 路径遍历和文件操作 +# 目录遍历 +from pathlib import Path + +folder = Path("src") + +# 遍历目录内容(非递归) +for item in folder.iterdir(): + print(item) + +# 使用通配符查找文件 +for py_file in folder.glob("*.py"): + print(py_file) + +# 递归查找文件 +for py_file in folder.rglob("*.py"): + print(py_file) + +# 目录创建 +# 创建单个目录 +new_folder = Path("new_directory") +new_folder.mkdir(exist_ok=True) # 已存在不报错 + +# 创建多级目录 +deep_folder = Path("level1/level2/level3") +deep_folder.mkdir(parents=True, exist_ok=True) + +# 常用遍历方法 +# 方法 描述 递归 +# iterdir() 列出目录内容 否 +# glob(pattern) 通配符查找 否 +# rglob(pattern) 递归查找 是 + + +# 通配符模式 +# *:匹配任意多个字符 +# ?:匹配单个字符 +# **:递归匹配(仅在 rglob 中有效) + +# 常用路径操作示例 +# 获取当前目录信息 +import os +from pathlib import Path + +# 获取当前工作目录 +current_dir = os.getcwd() # 返回字符串 +print(f"当前工作目录: {current_dir}") + +# 使用 pathlib 获取当前目录 +current_path = Path.cwd() # 返回 Path 对象 +print(f"当前路径: {current_path}") + +# 获取用户主目录 +home_dir = Path.home() +print(f"用户主目录: {home_dir}") + + +# 路径规范化 +from pathlib import Path + +# 处理相对路径和符号链接 +path = Path("../../Documents/../file.txt") +print(f"原始路径: {path}") +print(f"解析后路径: {path.resolve()}") + +# 计算相对路径 +base_path = Path("/home/user/documents") +target_path = Path("/home/user/documents/work/project/file.txt") +relative_path = target_path.relative_to(base_path) +print(f"相对路径: {relative_path}") # work/project/file.txt + +# 文件路径操作综合示例 +from pathlib import Path + +# 定义多种路径示例 +paths = [ + "/home/user/documents/report.pdf", + "relative/path/file.txt", + "../parent/file.py", + "file_no_extension", + "archive.tar.gz", +] + +# 分析每个路径 +for path_str in paths: + path = Path(path_str) + print(f"\n分析路径: {path}") + print(f"文件名: {path.name}") + print(f"主干名: {path.stem}") + print(f"扩展名: {path.suffix}") + print(f"父目录: {path.parent}") + print(f"是否为绝对路径: {path.is_absolute()}") + + +# 文件和目录操作 +# 文件操作 +# 使用 pathlib 进行文件操作更加简洁和安全 +from pathlib import Path + +# 创建文件并写入内容 +file_path = Path("test.txt") +file_path.write_text("Hello, World!", encoding="utf-8") + +# 读取文件内容 +content = file_path.read_text(encoding="utf-8") +print(content) + +# 获取文件信息 +if file_path.exists(): + stat = file_path.stat() + print(f"文件大小: {stat.st_size} 字节") + print(f"最后修改: {stat.st_mtime}") + +# 重命名文件 +new_path = file_path.rename("new_test.txt") + +# 文件操作优势 +# 简洁性:一行代码完成文件读写 +# 安全性:自动处理编码和异常 +# 跨平台:自动处理路径分隔符 +# 类型安全:更好的错误提示 + +# 目录操作 +# 创建目录 +from pathlib import Path +import shutil + +# 创建单个目录 +Path("example_dir").mkdir(exist_ok=True) + +# 创建多级目录 +Path("parent/child/grandchild").mkdir(parents=True, exist_ok=True) + +# 遍历目录 +# 遍历目录内容 +folder = Path("example_dir") +print("目录内容:") +for item in folder.iterdir(): + if item.is_dir(): + print(f"目录: {item.name}") + else: + print(f"文件: {item.name}") + +# 目录复制和删除 +# 复制整个目录 +shutil.copytree("example_dir", "copy_dir", dirs_exist_ok=True) + +# 删除空目录 +Path("empty_dir").mkdir(exist_ok=True) +Path("empty_dir").rmdir() + +# 删除非空目录 +shutil.rmtree("copy_dir") + +# 目录操作优势 +# 安全性:exist_ok=True 避免重复创建错误 +# 递归性:parents=True 自动创建父目录 +# 完整性:shutil 提供完整的目录操作 +# 跨平台:自动处理不同操作系统的差异 + +# 跨平台路径处理 + +# 操作系统检测 +from pathlib import Path +import os + +# 根据操作系统选择路径 +if os.name == "nt": # Windows + path = Path("C:/Users/Name/Documents") +else: # Unix/Linux/Mac + path = Path("/home/name/documents") + +# 路径拼接 +file_path = path / "subfolder" / "file.txt" +print(f"文件路径: {file_path}") + +# 转换为字符串 +path_str = str(file_path) +print(f"字符串路径: {path_str}") + +# 跨平台优势 +# 自动分隔符:pathlib 自动处理 / 和 \ +# 路径标准化:统一路径表示方式 +# 兼容性:代码在不同系统上都能正常工作 +# 类型安全:Path 对象提供更好的类型提示 + +# 实用函数示例 +# 文件查找函数 +from pathlib import Path + + +def find_files_by_extension(directory, extension): + """查找指定目录下指定扩展名的所有文件""" + directory_path = Path(directory) + return list(directory_path.rglob(f"*{extension}")) + + +# 使用示例 +python_files = find_files_by_extension(".", ".py") +print("找到的 Python 文件:") +for file in python_files: + print(f" {file}") + + +# 文件信息获取函数 +def get_file_info(file_path): + """获取文件的详细信息""" + path = Path(file_path) + if path.exists() and path.is_file(): + stat = path.stat() + return { + "name": path.name, + "size": stat.st_size, + "modified": stat.st_mtime, + "absolute_path": str(path.absolute()), + } + return None + + +# 使用示例 +if python_files: + file_info = get_file_info(python_files[0]) + print(f"文件信息: {file_info}") + +# 文件备份函数 +import shutil + + +def create_backup(file_path): + """创建文件备份""" + path = Path(file_path) + if path.exists() and path.is_file(): + backup_path = path.with_suffix(".bak") + shutil.copy2(path, backup_path) + return backup_path + return None + + +# 使用示例 +backup_file = create_backup("example.txt") +if backup_file: + print(f"备份文件: {backup_file}") + +# 实用函数优势 +# 模块化:每个函数专注单一功能 +# 可重用:可以在不同项目中重复使用 +# 错误处理:包含适当的错误检查 +# 类型安全:使用 Path 对象提供更好的类型支持 + +# 最佳实践 +# 10.1.路径操作原则 +# 使用 pathlib:新项目推荐使用 pathlib,更现代、更直观 +# 路径分隔符:使用 / 或 os.path.join(),避免直接使用 \ +# 路径检查:操作前检查路径是否存在 +# 异常处理:使用 try-except 处理路径操作错误 +# 跨平台兼容:确保代码在不同操作系统上都能正常工作 + +# 10.2.性能优化建议 +# 缓存路径对象:避免重复创建 Path 对象 +# 批量操作:使用 glob 和 rglob 进行批量文件操作 +# 路径规范化:使用 resolve() 获取规范路径 +# 内存管理:及时释放不需要的路径对象 + +# 10.3.安全注意事项 +# 路径验证:验证用户输入的路径 +# 权限检查:确保有足够的文件操作权限 +# 符号链接:注意符号链接可能带来的安全风险 +# 路径遍历:防止路径遍历攻击 diff --git a/20-24/08model-package.py b/20-24/08model-package.py new file mode 100644 index 0000000..125666a --- /dev/null +++ b/20-24/08model-package.py @@ -0,0 +1,528 @@ +# 概述 +# 模块和包是 Python 中组织代码的重要方式,它们让代码更加结构化、可维护和可重用。掌握模块和包的使用是 Python 编程的基础技能。 + +# 2.核心概念 +# 模块:包含 Python 定义和语句的 .py 文件 +# 包:包含多个模块的目录,必须有 __init__.py 文件 +# 命名空间:每个模块和包都有独立的命名空间 +# 导入:将模块或包引入当前程序的过程 +# 模块(Module) +# 3.1.什么是模块? +# 模块是一个包含 Python 定义和语句的 .py 文件,可以包含: + +# 函数定义 +# 类定义 +# 变量 +# 可执行代码 +# 3.2.模块的优势 +# 代码复用:公共函数/类可以集中管理 +# 命名空间隔离:避免命名冲突 +# 可维护性:分文件组织更易管理大型项目 +# 模块化设计:提高代码的模块化程度 + + +# 创建和使用模块 +# 创建模块 +# mymodule.py +def hello(): + print("Hello from mymodule!") + + +def add(a, b): + return a + b + + +class Calculator: + def multiply(self, a, b): + return a * b + + +# 导入模块 +# main.py +import mymodule + +# 使用模块中的函数和类 +mymodule.hello() +result = mymodule.add(3, 4) +calc = mymodule.Calculator() +print(calc.multiply(2, 3)) + +# 导入特定成员 +# 导入特定函数和类 +from mymodule import hello, add, Calculator + +# 直接使用,无需模块名前缀 +hello() +result = add(3, 4) +calc = Calculator() + +# 模块查找路径 +# Python 按照以下顺序查找模块: + +# 当前程序所在目录 +# PYTHONPATH 环境变量指定的目录 +# Python 安装时的标准库目录 +import sys + +# 查看模块搜索路径 +print(sys.path) + +# 模块命名规范 +# 使用小写字母和下划线 +# 避免与标准库同名 +# 导入时无需写 .py 后缀 + +# 导入方式详解 + +# 导入整个模块 +# import math + +# # 通过模块名访问成员 +# print(math.sqrt(16)) # 输出 4.0 +# print(math.pi) # 输出 3.141592653589793 + +# 1.优点 +# 命名空间清晰:明确成员来自哪个模块 +# 避免命名冲突:同名函数不会冲突 +# 代码可读性:容易理解函数来源 +# 2.适用场景 +# 使用模块中多个成员时 +# 需要明确函数来源时 +# 避免命名冲突时 + + +# 导入所有成员(import *) +# from 模块名 import * +# mymodule.py +def foo(): + print("foo") + + +def bar(): + print("bar") + + +from mymodule import * + +foo() # 输出 foo +bar() # 输出 bar + +# 控制导入内容 +# mymodule.py +__all__ = ["foo"] # 只允许导入 foo + + +def foo(): + print("foo") + + +def bar(): + print("bar") + + +# 注意事项 +# 不推荐使用:容易造成命名冲突 +# 仅限模块:不适用于包 +# 命名空间污染:直接暴露在当前命名空间 +# 可读性差:难以确定函数来源 + +# 推荐做法 +# 推荐:明确导入 +from mymodule import foo, bar + +# 推荐:导入整个模块 +import mymodule + + +# 使用别名 +# import 模块名 as 新名字 +# from 模块名 import 成员 as 新名字 +# 示例 +import numpy as np +import matplotlib.pyplot as plt +from math import factorial as fact + +# 使用别名 +arr = np.array([1, 2, 3]) +plt.plot([1, 2, 3]) +result = fact(5) + +# 别名优势 +# 代码简洁:缩短长模块名 +# 避免冲突:解决命名冲突 +# 社区约定:遵循常用别名习惯 + +# 常用别名 +# numpy → np +# pandas → pd +# matplotlib.pyplot → plt +# tensorflow → tf + + +# 模块的 __name__ 属性 +# __name__ 属性用于判断模块是被直接运行还是被导入: + + +# 直接运行时:__name__ 为 "__main__" +# 被导入时:__name__ 为模块名称 +# mymodule.py +def func(): + print("hello") + + +if __name__ == "__main__": + # 只在直接运行时执行 + func() + +# 使用场景 +# 运行方式 __name__ 值 作用 +# 直接运行 "__main__" 执行主流程 +# 被导入 模块名 提供接口 + +# 最佳实践 +# 所有模块入口脚本都使用 if __name__ == "__main__": +# 既可作为工具库导入,也可作为脚本运行 +# 提高代码的灵活性和可测试性 + + +# 包(Package) +# 5.1.什么是包? +# 包是组织多个模块的目录,包含: + +# 多个模块(.py 文件) +# 子包(嵌套目录) +# __init__.py 文件(必需) +# 5.2.包的优势 +# 项目结构清晰:分层组织代码 +# 避免命名冲突:独立的命名空间 +# 便于团队开发:模块化协作 +# 组件重用:可复用的代码单元 + +# 包的结构 +# mypackage/ +# ├── __init__.py # 包初始化文件(必需) +# ├── module1.py # 模块1 +# ├── module2.py # 模块2 +# └── subpackage/ # 子包 +# ├── __init__.py # 子包初始化文件 +# └── module3.py # 子包模块 + +# 创建包结构 +# 目录结构 +# myproject/ +# ├── main.py +# └── mypackage/ +# ├── __init__.py +# ├── module1.py +# ├── module2.py +# └── subpackage/ +# ├── __init__.py +# └── module3.py + + +# 初始化文件 __init__.py +# mypackage/__init__.py +"""mypackage 包的初始化文件""" + +__version__ = "1.0.0" +__author__ = "Your Name" + +# 导入包中的模块,方便用户使用 +from .module1 import function1 +from .module2 import Class2 + +# 定义包级别的变量 +package_variable = "这是包变量" + +print("mypackage 包被导入") + + +# 包中的模块 +# mypackage/module1.py +def function1(): + return "这是 module1 的 function1" + + +def helper_function(): + return "辅助函数" + + +# mypackage/module2.py +class Class2: + def __init__(self, value): + self.value = value + + def display(self): + return f"Class2 的值: {self.value}" + + +# mypackage/subpackage/module3.py +def function3(): + return "这是子包中的 function3" + + +# 导入包和模块语法 +# 导入整个包 +# 导入整个包(执行 __init__.py) +import mypackage + +# 导入包内模块 +# 导入包内指定模块 +from mypackage import module1 + +# 导入包中模块的成员 +from mypackage.module1 import function1 + +# 导入子包 +# 导入子包中的模块 +from mypackage.subpackage import module3 + +# 导入子包模块的成员 +from mypackage.subpackage.module3 import function3 + +# 相对导入与绝对导入 + +# 绝对导入 +# 从项目根包开始写完整路径: +# 从 mypackage 包中的 module1 模块导入 function1 函数 +from mypackage.module1 import function1 + +# 从子包中导入 +from mypackage.subpackage.module3 import function3 + +# 相对导入 +# 在包内部使用点号语法: +# 同级目录 +from . import module1 + +# 上一级包 +from .. import module2 + +# 同级模块 +from .module1 import func + +# 上级包的子包 +from ..subpackage import module3 + +# 注意事项 +# 相对导入只能用于包内部模块 +# 不能在最顶层脚本(main.py)中使用 +# 包内各文件的相对路径以包目录为基准 + +# __init__.py 的作用 +# 声明包:标识目录为 Python 包 +# 初始化操作:包级变量、配置、统一导入 +# 控制导入:通过 __all__ 列表控制可见成员 + +# 导入包和模块示例 +# main.py + +# 导入包中的特定模块 +from mypackage import module1 + +print(module1.function1()) + +# 导入包中的特定函数/类 +from mypackage.module2 import Class2 + +obj = Class2(42) +print(obj.display()) + +# 导入子包中的模块 +from mypackage.subpackage import module3 + +print(module3.function3()) + +# 使用 __init__.py 中导入的内容 +from mypackage import function1 + +print(function1()) + +# 导入包变量 +import mypackage + +print(mypackage.package_variable) + + +# 高级导入技巧 +# 相对导入 +# 相对导入在包内部使用点号语法引用同包或父包内容: +# 基本语法 +# from . import xxx:从当前包导入 +# from .. import xxx:从父包导入 +# from .subpackage import yyy:从子包导入 +# mypackage/ +# ├── __init__.py +# ├── module1.py +# ├── module2.py +# └── subpackage/ +# ├── __init__.py +# └── module3.py + +# module1.py +# from . import module2 # 导入同级模块 +# from .subpackage import module3 # 导入子包模块 + +# def function1(): +# return "这是 module1 的 function1" + +# 注意事项 +# 只能在包内部使用 +# 不能在主程序(main.py)中使用 +# 有助于包的重命名与迁移 +# 点数与目录层次相关 + +# 动态导入 +# 动态导入在程序运行时根据需要导入模块,常用于插件系统和可扩展框架。 + +# .使用 __import__() +module_name = "math" +math_module = __import__(module_name) +print(math_module.sqrt(9)) # 输出: 3.0 + +# 使用 importlib +import importlib + +# 导入标准库模块 +module = importlib.import_module("json") +data = module.loads('{"a": 1}') +print(data) # 输出: {'a': 1} + +# 导入包内模块 +module_name = "mypackage.module1" +mod = importlib.import_module(module_name) +result = mod.function1() +print(result) # 输出: 这是 module1 的 function1 + +# 动态导入优势 +# 按需加载:减少资源占用 +# 插件机制:支持动态扩展功能 +# 配置驱动:根据配置加载不同组件 + +# 注意事项 +# 确保模块名合法且可找到 +# 过度使用影响代码可读性 +# 仅在确有需要时使用 + +# 模块搜索路径 + +# 搜索路径顺序 +# Python 按以下顺序查找模块: +# 当前脚本所在目录 +# 标准库路径(如 /usr/lib/python3.x) +# 第三方库目录(如 site-packages) +# PYTHONPATH 环境变量指定的路径 + +# 查看和修改搜索路径 +import sys + +# 查看当前搜索路径 +print(sys.path) + +# 临时添加自定义路径 +sys.path.append("/path/to/your/modules") + +# 模块查找优先级 +# 内存缓存:已加载的模块(防止重复导入) +# 内建模块:如 sys、os +# sys.path 目录:按顺序逐一查找 + +# 最佳实践 +# 合理组织项目结构 +# 使用 __init__.py 标识包 +# 规范包和模块命名 +# 避免随意修改 sys.path + + +# 创建可安装的包 + +# 包目录结构 +# mypackage/ +# ├── mypackage/ +# │ ├── __init__.py +# │ ├── module1.py +# │ └── module2.py +# ├── tests/ +# │ └── test_module1.py +# ├── setup.py +# ├── README.md +# └── LICENSE + +# 创建步骤 +# 组织包目录结构 + +# 外层目录:项目根目录 +# 内层目录:实际包目录(包含 __init__.py) +# tests/:测试代码目录 + +# 创建 __init__.py +# 声明目录为 Python 包 +# 可包含包级初始化逻辑 + +# 编辑 setup.py 配置 +# 声明包名称、版本、依赖等元信息 + +# (可选)增加 MANIFEST.in +# 包含非 Python 文件(数据文件、README 等) + +# 安装和发布 +# 本地安装:pip install . 或 pip install -e . +# 发布到 PyPI:python setup.py sdist bdist_wheel 和 twine upload dist/* + +# 设置文件 setup.py +# setup.py +from setuptools import setup, find_packages + +setup( + name="mypackage", + version="1.0.0", + description="一个示例包", + author="Your Name", + packages=find_packages(), + install_requires=[ + "requests>=2.25.1", + "numpy>=1.19.5", + ], + python_requires=">=3.6", +) +# 安装和发布 +# 开发模式安装(可编辑模式) +pip install -e . + +# 构建分发包 +python setup.py sdist bdist_wheel + +# 上传到PyPI +twine upload dist/* + + +# 最佳实践 +# 1.命名规范 +# 模块命名:使用小写字母和下划线 +# 包命名:使用小写字母,避免使用下划线 +# 避免冲突:不与标准库同名 + +# 2.导入规范 +# 导入顺序:标准库 → 第三方库 → 本地模块 +# 避免循环导入:模块间相互导入 +# 使用 if __name__ == "__main__":区分直接运行和导入 + +# 导入顺序示例 +# 标准库 +import os +import sys +from datetime import datetime + +# 第三方库 +import requests +import numpy as np + +# 本地模块 +from mypackage import module1 +from mypackage.subpackage import module2 + +# 项目组织 +# 合理使用包和模块 +# 避免过深的嵌套结构 +# 保持模块功能单一 +# 编写清晰的文档和注释 \ No newline at end of file diff --git a/20-24/09fanshe.py b/20-24/09fanshe.py new file mode 100644 index 0000000..710d7e2 --- /dev/null +++ b/20-24/09fanshe.py @@ -0,0 +1,253 @@ +# 反射(Reflection)是指在程序运行时检查、访问和修改其自身状态和行为的能力。Python 作为一种高度动态的语言,天然支持强大的反射机制。 + +# 2.核心价值 +# 动态性:在运行时操作对象 +# 灵活性:根据条件动态调用方法 +# 通用性:编写可重用的通用代码 +# 内省:检查对象的结构和能力 + +# 核心函数 +# 函数 描述 返回值 +# hasattr(obj, name) 检查对象是否有指定属性 布尔值 +# getattr(obj, name[, default]) 获取对象属性值 属性值或默认值 +# setattr(obj, name, value) 设置对象属性值 None +# delattr(obj, name) 删除对象属性 None +# dir(obj) 获取对象所有属性和方法 列表 + + +# 基本用法 + + +class Example: + def __init__(self): + self.value = 42 + + +example = Example() +# 检查属性是否存在 +print(hasattr(example, "value")) # True +# 获取某个属性值 +print(getattr(example, "value")) # 42 +# 设置新属性 +setattr(example, "new_attr", 100) +print(getattr(example, "new_attr")) # 100 + +# 删除属性 +delattr(example, "new_attr") +print("new_attr" in dir(example)) # False + +print(dir(example)) + +# 安全属性访问 + + +class Config: + def __init__(self): + self.host = "localhost" + self.port = "8080" + + +config = Config() +timeout = getattr(config, "timeout", 300) # 如果不存在设置默认值 +print(timeout) # 返回默认值 +print("timeout" in dir(config)) # False 不会设置上去 + + +# 内省函数 +# 4.1.类型检查函数 +# 函数 描述 示例 +# type(obj) 返回对象类型 type(123) → +# isinstance(obj, class) 检查对象是否为指定类型 isinstance(123, int) → True +# issubclass(cls, class) 检查类继承关系 issubclass(Bar, Foo) → True + + +# 对象信息函数 +# 函数 描述 示例 +# dir(obj) 获取对象所有属性和方法 dir(obj) → ['attr1', 'method1', ...] +# vars(obj) 获取对象的属性字典 vars(obj) → {'attr1': 'value1'} +# obj.__dict__ 对象的属性字典 obj.__dict__ → {'attr1': 'value1'} + + +# 示例 +class Foo: + def __init__(self): + self.attr1 = "hello" + + +class Bar(Foo): + def method1(self): + return "world" + + +foo = Foo() +bar = Bar() + + +# 类型 +print(type(foo)) # +print(isinstance(bar, Foo)) # True +print(issubclass(Bar, Foo)) # True + +# 对象信息 +print(hasattr(foo, "attr1")) # True +print(getattr(foo, "attr1")) # hello +print(vars(foo)) # {'attr1': 'hello'} +print(vars(bar)) # {'attr1': 'hello'} +print( + dir(foo) +) # ['__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__', 'attr1'] + + +def show_object_members(obj): + print(f"对象类型: {type(obj)}") + for attr in dir(obj): + if attr.startswith("_"): + continue + value = getattr(obj, attr) + if callable(value): + print(f"[方法] {attr}()") + else: + print(f"[属性] {attr} = {value}") + + +# 使用示例 +show_object_members(123) + + +# 类级别反射是指直接作用于类本身的反射操作,可以: + +# 动态获取和修改类属性(包括类变量) +# 调用类方法和静态方法 +# 检查类中的方法和属性是否存在 +# 动态给类添加属性或方法 + + +class DatabaseModel: + table_name = "users" + connection_string = "sqlite:///database.bd" + + def __init__(self, id, name): + self.id = id + self.name = name + + # @classmethod 装饰器可以将方法包装成类方法,类方法直接通过类来调用,不需要创建实例 + @classmethod + def get_table_info(cls): + return f"表名:{cls.table_name},连接{cls.connection_string}" + + # @staticmethod 将方法变为静态方法。静态方法既可以通过类来调用,也可以通过实例来调用,但他们并不会接受任何饮食的第一参数(既不接受类对象,也不接受实例对象) + @staticmethod + def validata_data(data): + return isinstance(data, dict) + + def save(self): + return f"保存{self.name}到数据库中" + + +# 类级别的反射操作 +print(getattr(DatabaseModel, "table_name")) +print(getattr(DatabaseModel, "connection_string")) + +# 动态修改属性 +setattr(DatabaseModel, "table_name", "customers") +print(getattr(DatabaseModel, "table_name")) # customers + +# 调用类的方法 +class_method = getattr(DatabaseModel, "get_table_info") +print(class_method()) + +# 调用静态方法 +static_method = getattr(DatabaseModel, "validata_data") +print(static_method({"key": "val"})) # True + +# 检查类成员 +print(hasattr(DatabaseModel, "table_name")) # True +print(hasattr(DatabaseModel, "connection_string")) # True +print(hasattr(DatabaseModel, "get_table_info")) # True + + +# 模块级别反射 +# 7.1.概念 +# 模块级反射是指在运行时动态地检查、导入、操作模块及其内容的能力。它可以帮助我们开发出高度可配置、插件化、支持热加载的系统。 + +# 7.2.常用函数 +# 函数 描述 示例 +# importlib.import_module(name) 按名称动态导入模块 importlib.import_module("math") +# getattr(module, name[, default]) 动态获取模块中的函数、类、变量 getattr(math, "sqrt") +# hasattr(module, name) 判断模块是否有某个属性 hasattr(math, "pow") +# dir(module) 获取模块内定义的名称列表 dir(math) +# importlib.reload(module) 重新加载已加载的模块 importlib.reload(math) + + +# 基本示例 +import importlib +from typing import Any + +# 动态导入模块 +module_name = "math" +math_mod = importlib.import_module(module_name) +print( + math_mod +) # +print(getattr(math_mod, "sqrt")(16)) # 4.0 + +# 检查是否存在某属性 +if hasattr(math_mod, "pow"): + print(math_mod.pow(2, 8)) # 256.0 + + +# 应用场景 + +# 配置系统 + + +class ConfigManager: + def __init__(self, config_dict=None): + self._config = config_dict or {} + self._defaultConfig = { + "debug": False, + "host": "localhost", + "port": 8080, + "timeout": 30, + } + + def __getattr__(self, name): + if name in self._config: + return self._config.get(name) + elif name in self._defaultConfig: + return self._defaultConfig.get(name) + else: + raise ArithmeticError(f"配置选项不存在{name}") + + def set_config(self, **kwargs): + for key, val in kwargs.items(): + self._config[key] = val + + def show_config(self): + all_config = {**self._defaultConfig, **self._config} + for key, val in all_config.items(): + source = "默认" if key in self._defaultConfig else "自定义" + print(f"{key}:{val}[{source}]") + + +config = ConfigManager() +print(f"Host: {config.host}") # localhost +print(f"Port: {config.port}") # 8080 +print(f"Debug: {config.debug}") # False + +config.set_config(host="127.0.0.1", port=9000, new_setting="custom") +print("\n所有配置:") +config.show_config() + + +requests = [ + ("GET", "/users"), + ("GET", "/users/123"), + ("POST", "/users", {"name": "Alice", "email": "alice@example.com"}), + ("PUT", "/users/123", {"name": "Alice Smith"}), + ("DELETE", "/users/123"), +] + +# *args 会返回一个list +for method, path, *args in requests: + params = args[0] if args else {} diff --git a/20-24/10error.py b/20-24/10error.py new file mode 100644 index 0000000..036f482 --- /dev/null +++ b/20-24/10error.py @@ -0,0 +1,129 @@ +# 异常 + +# 具体的异常捕获 +try: + with open("abc.text", "r") as f: + data = f.read() +except FileNotFoundError: + print("文件不存在") +except PermissionError: + print("没有权限") +except OSError: + print("系统错误") + +# 避免空的except块 +# try: +# risky_operation() +# except SpecificError as e: +# logger.error(f"操作失败", e) +# # 或者采取其他的操作 + +# 资源清理 +# with open("abc.txt", "r") as f: +# data = f.read() +# process_data(data) + + +# 异常日志记录 +import logging + +# 配置日志模块 +logging.basicConfig(level=logging.ERROR) + + +# 数据库报错 +class DataBaseError(Exception): + pass + + +# 校验用户数据是否有效 +class ValidationError(Exception): + pass + + +# 根据id从数据库中查询数据 +def get_user_from_db(user_id): + if user_id == 0: + raise DataBaseError("数据库连接失败") + return {"user_id": user_id, "user_name": "小明", "age": 20} + + +# 校验拿到的当前用户信息是否合法 +def validate_and_process(user_data): + if not user_data["user_name"] or user_data["age"] < 0: + raise ValidationError("用户信息无效") + user_data["process"] = True + return user_data + + +def process_user_data(user_id): + try: + user_data = get_user_from_db(user_id) + result = validate_and_process(user_data) + return result + except DataBaseError as e: + logging.error(f"数据库错误-用户ID:{user_id},错误{e}") + raise + except ValidationError as e: + logging.error(f"用户信息错误,用户ID{user_id},错误{e}") + return None + except Exception as e: + logging.critical(f"未知错误,用户ID{user_id},错误{e}") + raise + + +# result = process_user_data(0) +# print(result) + + +# 数据验证 +class DataValidator: + + @staticmethod + def validate_email(email): + if not isinstance(email, str): + raise TypeError("邮箱必须是字符串") + if "@" not in email: + raise ValueError("无效的邮箱格式") + return email.lower() + + @staticmethod + def validate_age(age): + if not isinstance(age, int): + raise TypeError("年龄必须是整数") + if age < 0 or age > 160: + raise ValueError("年龄必须在0~160之间") + return age + + def validate_user_data(user_data): + error = {} + try: + user_data["email"] = DataValidator.validate_email(user_data["email"]) + except (TypeError, ValueError) as e: + error["email"] = str(e) + + try: + user_data["age"] = DataValidator.validate_age(user_data["age"]) + except (TypeError, ValueError) as e: + error["age"] = str(e) + if error: + raise ValidationError("数据验证失败", error) + + +class ValidationError(Exception): + def __init__(self, message, errors): + self.message = message + self.errors = errors + super().__init__(self.message) + + +# 测试用例 +user_input = {"email": "invalid-email", "age": 200} + +try: + validate_data = DataValidator.validate_user_data(user_input) + print(f"数据验证成功,{validate_data}") +except ValidationError as e: + print(f"数据验证失败{e.message}") + for field, error in e.errors.items(): + print(f"{field}:{error}") diff --git a/20-24/11yibu.py b/20-24/11yibu.py new file mode 100644 index 0000000..0a91d6e --- /dev/null +++ b/20-24/11yibu.py @@ -0,0 +1,11 @@ +import asyncio + + +async def my_coroutine(): + print("协程开始执行") + await asyncio.sleep(10) + print("协程结束") + return "协程结果" + + +asyncio.run(my_coroutine()) diff --git a/20-24/12reduce.py b/20-24/12reduce.py new file mode 100644 index 0000000..6f52fcd --- /dev/null +++ b/20-24/12reduce.py @@ -0,0 +1,41 @@ +# reduce + +# 核心概念概述 +# reduce函数是Python的内置函数,它的主要作用是对可迭代对象中的元素进行累积操作,将序列中的元素通过指定的函数逐步合并,最终得到一个单一的结果。 + +# 作用:对序列进行累积操作,将多个元素合并为一个结果 +# 导入:需要从functools模块导入 +# 参数:接受一个函数和一个可迭代对象 +# 函数式编程:支持函数式编程范式 + +# from functools import reduce +# reduce(function, iterable[, initializer]) + +# function:累积函数,必须接受两个参数 +# iterable:可迭代对象(如列表、元组等) +# initializer:可选参数,作为累积的初始值 + +from functools import reduce + + +def add(x, y): + return x + y + + +numbers = [1, 2, 3, 4, 5] + +result = reduce(add, numbers) +print(result) + +# 模拟reduce +# 默认初始值 + + +def MyRduce(numbers): + accumulator = numbers[0] + for i in range(1, len(numbers)): + accumulator += numbers[i] + return accumulator + + +print(MyRduce(numbers)) diff --git a/20-24/13zip.py b/20-24/13zip.py new file mode 100644 index 0000000..dd3793a --- /dev/null +++ b/20-24/13zip.py @@ -0,0 +1,69 @@ +# zip函数的基本用法 +# 2.1 概念说明 +# zip函数的基本用法是将多个可迭代对象打包成一个迭代器,每次迭代返回一个包含每个输入对象中对应元素的元组。 + +list1 = [1, 2, 3] +list2 = ["a", "b", "c"] +tuple3 = ("q", "w", "f") +result_zip = zip(list1, list2, tuple3) +# print(list(result_zip)) # [(1, 'a', 'q'), (2, 'b', 'w'), (3, 'c', 'f')] + +for item1, item2, item3 in result_zip: + print(f"{item1}:{item2}:{item3}") + + +# zip函数的拆包技巧 +# 3.1 概念说明 +# zip函数不仅可以"压缩"多个列表,还可以使用*操作符进行反向操作,将压缩后的结果"解压"回原来的形式。 +zipped = [(1, "a"), (2, "b"), (3, "c")] +list1, lis2 = zip(*zipped) +print(list1) +print(lis2) + + +matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +transposed = list(zip(*matrix)) +print(transposed) # [(1, 4, 7), (2, 5, 8), (3, 6, 9)] + +transposed_list = [item for sublist in matrix for item in sublist] +print(transposed_list) + + +# 处理不同长度的可迭代对象 +# 4.2 概念说明 +# 默认情况下,zip函数会在最短的输入可迭代对象耗尽时停止。对于需要处理不同长度可迭代对象的场景,可以使用itertools.zip_longest函数。 +# 定义不同长度的列表 +list1 = [1, 2, 3, 4, 5] +# 定义第一个列表(较长) +list2 = ["a", "b"] +# 定义第二个列表(较短) +list3 = [1.1, 2.2, 3.3] +# 定义第三个列表(中等长度) + +# 使用普通zip函数 +print("1. 使用普通zip函数:") +# 打印使用普通zip函数标题 +result_normal = zip(list1, list2, list3) +# 使用普通zip函数压缩列表 +print(f"普通zip结果: {list(result_normal)}") # [(1, 'a', 1.1), (2, 'b', 2.2)] + +from itertools import zip_longest + +# fillvalue 填充值 使用None作为填充值(默认) +result_longest = zip_longest(list1, list2, list3, fillvalue="x") +print( + list(result_longest) +) # [(1, 'a', 1.1), (2, 'b', 2.2), (3, 'x', 3.3), (4, 'x', 'x'), (5, 'x', 'x')] + + +csv_data = [ + ["Name", "Age", "City"], + ["Alice", "25"], + ["Bob", "30", "New York", "Engineer"], + ["Charlie", "35", "London"], +] + +processed_data = list(zip_longest(*csv_data, fillvalue="")) +print( + processed_data +) # [('Name', 'Alice', 'Bob', 'Charlie'), ('Age', '25', '30', '35'), ('City', '', 'New York', 'London'), ('', '', 'Engineer', '')] diff --git a/20-24/14anyheall.py b/20-24/14anyheall.py new file mode 100644 index 0000000..19c5c1c --- /dev/null +++ b/20-24/14anyheall.py @@ -0,0 +1,28 @@ +# 在Python中,any()和all()是两个重要的内置函数,用于对可迭代对象(如列表、元组、集合、字典、字符串等)中的元素执行布尔运算。这两个函数都采用短路求值(short-circuit evaluation)策略,能够高效地处理大量数据。 + +truthy_list = [1, 2, 3] +# 使用all()检查是否所有值都为真 +print(f"all([1, 2, 3]): {all(truthy_list)}") # 输出: True + + +alsy_list = [0, False, None] +# 使用any()检查是否有真值 +print(f"any([0, False, None]): {any(alsy_list)}") # 输出: False + +abc = [] + +if not abc: + print("1") +else: + print("2") + + +# # 应用 +# def test_fuc(x): +# return bool(x) + + +# tset_list = [0, 1, 2, 3, 4] + +# result = all(map(lambda x: test_fuc(x), tset_list)) +# print(result) diff --git a/20-24/15chongzai.py b/20-24/15chongzai.py new file mode 100644 index 0000000..0b67f0e --- /dev/null +++ b/20-24/15chongzai.py @@ -0,0 +1,89 @@ +# 类型分发与functools.singledispatch +# 5.1 singledispatch的基本概念: +# 尽管Python没有内置的函数重载,但标准库中的functools.singledispatch装饰器提供了一种实现单分派泛型函数(single-dispatch generic function)的机制。这意味着同一个函数名可以根据其第一个参数的类型来调用不同的实现。这在一定程度上模拟了基于类型的函数重载。 + +# 5.2 什么是单分派?如何用来实现“伪重载”? +# 单分派(single-dispatch)是一种“根据第一个参数的类型来自动选择函数实现”的机制,类似于其他语言中的“基于类型的函数重载”。 +# 在Python中,可以借助functools.singledispatch装饰器,让同一个函数名有多个实现,具体调用哪个实现由第一个参数的类型自动决定。 + +# 单分派的核心特点: + +# “重载”仅对第一个参数生效(后面的参数类型不会影响分派)。 +# 每个实现用.register(类型)方式绑定到主函数。 +# 如果没有匹配的类型,就会走“默认实现”。 +# 本质上这是一种“类型分发”(Type Dispatch)机制,而不是传统意义上的多参数重载。 +# 适用场景举例: + +# 序列化/反序列化不同类型数据 +# 数据处理框架按输入类型走不同逻辑 +# 实现API或工具函数对各类对象采用差异化策略 + +# 实际开发中,@singledispatch 不仅可以用来简化对不同类型参数的分支判断,还可以根据需求扩展更加复杂的类型分发逻辑。 + +# 假设我们要实现一个serialize_data函数,根据参数的数据类型不同,对其进行不同方式的序列化。我们可以为常见的类型——如str、int、float、list、dict等——分别注册对应的序列化方法,这样无需编写冗长的if-elif-else判断。遇到未注册的新类型时,自动调用默认序列化逻辑。 + +# 这种方式不仅让代码更优雅,可维护性增强,而且易于扩展和复用:后续只需新增注册实现即可轻松支持新的类型处 + +from functools import singledispatch + + +@singledispatch +def serialize_data(data): + return str(data) + + +# 根据字典类型类型注册序列化方法 +@serialize_data.register(dict) +def _(data): + result = [] + for key, val in data.items(): + result.append(f"{key}:{val}") + return "{" + ",".join(result) + "}" + + +# 根据列表注册序列化方法 +@serialize_data.register(list) +def _(data): + return "[" + ",".join(map(str, data)) + "]" + + +@serialize_data.register(str) +def _(data): + return f"{data}" + + +@serialize_data.register(int) +def _(data): + return f"整数{data}" + + +@serialize_data.register(float) +def _(data): + return f"浮点数{data}" + + +dict_data = {"name": "Alice", "age": 30} +print(f"字典序列化: {serialize_data(dict_data)}") + +list_data = [1, 2, 3, 4, 5] +print(f"列表序列化: {serialize_data(list_data)}") +# 输出: 列表序列化: [1, 2, 3, 4, 5] + +# 序列化字符串 +str_data = "Hello World" +print(f"字符串序列化: {serialize_data(str_data)}") +# 输出: 字符串序列化: "Hello World" + +# # 序列化整数 +int_data = 42 +print(f"整数序列化: {serialize_data(int_data)}") +# 输出: 整数序列化: 整数: 42 + +# 序列化浮点数 +float_data = 3.14159 +print(f"浮点数序列化: {serialize_data(float_data)}") +# # 输出: 浮点数序列化: 浮点数: 3.14 + +# # 序列化其他类型(使用默认方法) +bool_data = True +print(f"布尔值序列化: {serialize_data(bool_data)}") diff --git a/20-24/16scope.py b/20-24/16scope.py new file mode 100644 index 0000000..cec621b --- /dev/null +++ b/20-24/16scope.py @@ -0,0 +1,137 @@ +# 变量的作用域(scope)指的是一个变量在程序中可以被访问的范围。Python中的变量作用域遵循LEGB规则,即按照以下顺序查找变量: + +# L (Local):局部作用域 +# E (Enclosing):嵌套作用域 +# G (Global):全局作用域 +# B (Built-in):内置作用域 +# 基本特点 + +# 局部作用域:函数内部定义的变量,只能在函数内部访问 +# 嵌套作用域:嵌套函数中外层函数的变量对内层函数可见 +# 全局作用域:模块级别定义的变量,在整个模块中可见 +# 内置作用域:Python内置的函数和变量 + + +# 定义一个外层函数outer_function +def outer_function(): + # 在外层函数中定义一个变量y,并赋值为20 + y = 20 + print(f"外层函数中的y: {y}") + + # 在外层函数内部定义一个内层函数inner_function + def inner_function(): + # 内层函数可以访问外层函数的变量y + print(f"内层函数访问外层变量y: {y}") + # 预期输出: 内层函数访问外层变量y: 20 + + # 调用内层函数 + inner_function() + + # 在外层函数中再次打印y + print(f"外层函数中y的值: {y}") + + +# 调用外层函数 +outer_function() + + +# 全局作用域的修改 +# 在嵌套作用域中,内层函数可以“读取”外层函数的变量,但如果要“直接修改”外层变量,会遇到限制。 +# 默认情况下,如果你在内层函数中为某个变量赋值,这个变量会被视为“局部变量”,而不是外层的同名变量。这种行为可能会导致UnboundLocalError错误 + + +def outer(): + num = 10 # 外层变量 + + def inner(): + # 尝试直接修改外层变量,会报错 + try: + num += 1 # 内层函数会认为num是自己的局部变量 + except UnboundLocalError as e: + print(f"错误: {e}") + + inner() + print(f"最终num: {num}") + + +outer() +# 输出: 错误: local variable 'num' referenced before assignment +# 最终num: 10 + +# 在Python中,如果想在函数内部修改全局变量,必须用global关键字声明该变量属于全局作用域,否则Python会将其当作一个新的局部变量,导致修改的只是函数内部的“影子”变量,而不是外部真正的全局变量。 + +# 总结: + +# 只读全局变量时可直接在函数内引用; +# 想在函数内修改全局变量值,必须加global关键字; +# 否则会创建/修改局部变量,不会影响全局作用域中的变量值。 + +global_var = 100 + + +def modify_global(): + global global_var + global_var += 10 + print(f"函数内部修改后的global_var{global_var}") # 110 + + +modify_global() +print(f"函数外部的global_var{global_var}") # 110 + + +# nonlocal关键字的高级用法 +# 在嵌套函数中修改外层嵌套函数的变量 + +print("----------nonlocal--------------------") + + +def complex_outer(): + outer_var = "外层变量" + count = 0 + + def middle_function(): + middle_var = "中层变量" + + def inner_function(): + nonlocal outer_var, count + outer_var = "被内层函数修改" + count += 1 + print(f"内层函数修改外层变量: {outer_var}") + print(f"内层函数修改计数器: {count}") + + inner_function() + print(f"中层函数检查中层变量: {middle_var}") + + middle_function() + print(f"外层函数检查外层变量: {outer_var}") + print(f"外层函数检查计数器: {count}") + + +complex_outer() + + +# 定义一个全局变量 +conflict_var = "全局变量" +print(f"初始全局变量: {conflict_var}") + + +# 定义一个函数来演示变量名冲突 +# 这是一个作用域冲突导致的语法错误。 +# 解决方案 将 global 声明放在函数开头(推荐) + + +# def conflict_demo(): +# # 在函数内部定义同名变量 +# conflict_var = "局部变量" +# print(f"函数内部局部变量: {conflict_var}") + +# # 如果要访问全局变量,需要使用global关键字 +# global conflict_var +# print(f"使用global后的全局变量: {conflict_var}") + + +# # 调用函数 +# conflict_demo() + +# # 检查全局变量 +# print(f"函数外部全局变量: {conflict_var}") diff --git a/20-24/17bibao.py b/20-24/17bibao.py new file mode 100644 index 0000000..86b2818 --- /dev/null +++ b/20-24/17bibao.py @@ -0,0 +1,90 @@ +# 详细说明闭包的概念、工作原理、使用场景、优势以及在实际开发中的应用价值 + +# 1. 闭包概述 +# 闭包(Closure)是Python中的一种独特的函数机制。简而言之,闭包是指在一个内部函数中,引用了外部函数的变量,而这个外部函数已经执行完毕并返回了内部函数,然而内部函数仍然可以访问这些外部函数中的变量。 + +# 核心特点 + +# 内部函数:闭包涉及内部函数和外部函数 +# 变量引用:内部函数引用外部函数的变量 +# 状态保持:外部函数执行完毕后,内部函数仍能访问外部变量 +# 数据封装:通过闭包可以实现数据的封装和隐藏 + + +def out_function(x): + def inner_function(y): + return x + y + + return inner_function + + +func = out_function(1) +result = func(4) +print(result) + +# 闭包和作用域链 +# 闭包依赖于 Python 的词法作用域规则:内部函数会自动捕获其外部作用域内用到的变量,这些变量在外部函数生命周期结束后也不会被销毁。 + +# 2.2.3 使用 nonlocal 修改闭包变量 +# 通常,闭包内部只能“读取”外部变量。如果想在内部函数中“修改”外部函数的变量,需要使用 nonlocal 关键字。例如: + + +def make_accumulator(base=0): + total = base + + def add(num): + nonlocal total + total += num + return total + + return add + + +acc = make_accumulator(10) +print(acc(20)) +print(acc(-1)) + + +# 简单的装饰器 +def my_decorator(func): + def wrapper(*args, **kwargs): + print(f"调用函数:{func.__name__}") + result = func(*args, **kwargs) + print(f"函数 {func.__name__} 执行完成") + return result + + return wrapper + + +@my_decorator +def greet(name): + return f"Hello,{name}" + + +result = greet("小明") +print(result) + +# 带参数的装饰器 + + +def repeat(num): + def decorator(func): + def warpper(*args, **kwargs): + results = [] + for i in range(num): + result = func(*args, **kwargs) + results.append(result) + return results + + return warpper + + return decorator + + +@repeat(3) +def say_hello(name): + return f"Hello {name}" + + +results = say_hello("小明") +print(results) diff --git a/20-24/abc.py b/20-24/abc.py new file mode 100644 index 0000000..0271c5d --- /dev/null +++ b/20-24/abc.py @@ -0,0 +1,28 @@ +from collections import defaultdict, Counter +from datetime import datetime, timedelta +import random + +data = { + "users": [ + { + "id": i, + "name": f"User_{i}", + "age": random.randint(18, 60), + "join_date": ( + datetime.now() - timedelta(days=random.randint(0, 365)) + ).strftime("%Y-%m-%d"), + "score": random.randint(50, 100), + } + for i in range(1, 11) + ] +} +users = data["users"] +age_distribution = Counter(user["age"] for user in users) +# print(age_distribution) +# for age, count in age_distribution.items(): +# print(f"{age}岁的人数{count}") + + +now = datetime.now() +print(f"当前时间{now}") +print(type(now)) diff --git a/20-24/data.txt b/20-24/data.txt new file mode 100644 index 0000000..d800886 --- /dev/null +++ b/20-24/data.txt @@ -0,0 +1 @@ +123 \ No newline at end of file diff --git a/20-24/example.txt b/20-24/example.txt new file mode 100644 index 0000000..0c5dd2b --- /dev/null +++ b/20-24/example.txt @@ -0,0 +1,3 @@ +12 +34 +56 \ No newline at end of file diff --git a/20-24/image.png b/20-24/image.png new file mode 100644 index 0000000..48719c6 Binary files /dev/null and b/20-24/image.png differ diff --git a/20-24/js.js b/20-24/js.js new file mode 100644 index 0000000..4f9d873 --- /dev/null +++ b/20-24/js.js @@ -0,0 +1,6 @@ +let counter = 0; +function num() { + counter += 2; +} +num(); +console.log(counter); diff --git a/20-24/lianxi-Iterator.py b/20-24/lianxi-Iterator.py new file mode 100644 index 0000000..40fc240 --- /dev/null +++ b/20-24/lianxi-Iterator.py @@ -0,0 +1,191 @@ +# 手动实现一个自定义迭代器 + +# 我们可以通过定义一个类并实现__iter__()和__next__()方法来创建一个自定义的迭代器。 + + +class MyCustomIterator: + def __init__(self, data): + self.data = data + self.index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.index < len(self.data): + result = self.data[self.index] + self.index += 1 + return result + else: + raise StopIteration + + +my_inter_instance = MyCustomIterator([1, 2, 3]) +for item in my_inter_instance: + print(item) + +# 再次尝试遍历同一个迭代器实例,会发现它已经耗尽 +print("\n--- 再次遍历已耗尽的自定义迭代器 ---") +# 没有任何输出,此时my_inter_instance迭代器已耗尽 +for item in my_inter_instance: + print(item) + + +# 迭代器 +class MyCustomIterator: + def __init__(self, data): + self.data = data + self.index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.index < len(self.data): + result = self.data[self.index] + self.index += 1 + return result + else: + raise StopIteration + + +# 可迭代对象 +# Iterable 可迭代对象:实现了__iter__()方法,每次都都会返回一个新的Iterable 实例 +class MyIterable: + def __init__(self, data): + self.data = data + + def __iter__(self): + return MyCustomIterator(self.data) + + +# 可以遍历多次 +print("\n--- 可以遍历多次 ---") +my_interbale = MyIterable([1, 2, 3]) +# 第一次遍历 +print("第一次遍历") +for item in my_interbale: + print(item) +# 第二次遍历 +print("第二次遍历") +for item in my_interbale: + print(item) +# 验证每次iter()都会创建新的Iterator +print("验证每次iter()都会创建新的Iterator") +iterable = MyIterable([1, 2, 3]) +it1 = iter(iterable) +it2 = iter(iterable) +print(f"两个Iterator是否是同一个对象{it1 is it2}") # False +print(f"it1: {list(it1)}") +print(f"it2: {list(it2)}") + + +# Generator (生成器) +# 5.1 概念与特点 +# 生成器是Python中的一种特殊类型的迭代器,它允许你在迭代过程中逐渐生成值,而不是一次性生成所有的值。生成器由函数创建,这些函数使用yield关键字而不是return来返回值。 + +# 基本特点: + +# 惰性求值:只在需要时才生成值,节省内存 +# 状态保持:函数在yield后暂停,保持内部状态 +# 迭代器协议:遵循Python的迭代器协议 +# 内存友好:特别适合处理大数据集 +# 代码简洁:比手动实现迭代器更简洁 + +# 生成器函数 + + +def simple_gen(): + yield 1 + yield 2 + yield 3 + + +gen = simple_gen() +print(next(gen)) # 1 +print(next(gen)) # 2 +print(next(gen)) # 3 + +try: + print(next(gen)) +except StopIteration: + print("生成器函数耗尽,没有更多值") + + +def num_generator(): + yield 1 + yield 2 + yield 3 + yield 4 + yield 5 + + +gen = num_generator() +# 通过for循环生成器,会自动调用next()进行执行 +for num in gen: + print(num) + + +# yield关键字的工作原理 +# yield是Python中用于创建生成器函数的一个关键字。与return语句类似,它也可以从函数返回值,但不同之处在于: + +# 当函数执行到yield语句时,它会暂停执行并将yield后的值返回给调用者 +# 函数的状态(包括局部变量和指令指针)会被保存下来 +# 在下次调用时从暂停的地方继续执行,而不是像return那样彻底退出函数 + + +# 生成器表达式 +# 除了生成器函数,Python还支持生成器表达式。它们与列表推导式(list comprehensions)语法类似,但使用圆括号()而不是方括号[],并且返回的是一个生成器对象,而不是一个完整的列表。 + +# 生成器在处理数据时具有显著的优势: +# 内存效率高:生成器采用"惰性评估"(lazy evaluation)机制,不会立即将所有元素生成并存储在内存中,而是按需生成 +# 处理大数据流:非常适合处理网络数据流、文件读取等场景,因为数据可以逐块处理 + +# 基本语法 +print("生成器表达式") +my_gen = (x**2 for x in range(5)) +print(f"{type(my_gen)}") # +for item in my_gen: + print(item) + + +# 高级特性 +# 双向通信 (send()方法) +# 生成器不仅可以向调用者返回值,还可以通过send()方法从调用者接收值。这使得生成器能够实现更复杂的协程(coroutine)行为。 + + +# 定义一个支持双向通信的生成器函数 +def double_yield(): + # 第一个yield会暂停并等待外部send()发送值,将接收到的值赋给x + # 注意:第一次启动生成器时,next()或send(None)会使这个yield接收None + x = yield + # 进入无限循环,持续进行双向通信 + while True: + # 暂停并返回x * 2的值,同时等待外部send()发送新的值给x + x = yield x * 2 + + +gen = double_yield() +next(gen) # 启动生成器 + +print(gen.send(10)) + +print(gen.send(2)) + +# 异常处理 (throw()和close()方法) +# 生成器提供了其他方法来控制其生命周期和行为: + + +def exception_hanlding_generator(): + try: + while True: + yield "正在运行中" + except GeneratorExit: + print("生成器关闭") + finally: + print("生成器清理完成") + + +gen = exception_hanlding_generator() +print(next(gen)) +gen.close() diff --git a/20-24/lianxi-Lambda.py b/20-24/lianxi-Lambda.py new file mode 100644 index 0000000..cf61cb5 --- /dev/null +++ b/20-24/lianxi-Lambda.py @@ -0,0 +1,52 @@ +# Lambda函数,也称为匿名函数,是Python中一种轻量级、简洁的函数定义方式。与常规的def函数不同,Lambda函数没有名字,可以在需要短小函数的地方直接使用。 + +# 基本特点: + +# 匿名性:Lambda函数没有函数名 +# 简洁性:通常用于简单的单行表达式 +# 临时性:适合临时使用的功能 +# 函数式编程:与高阶函数配合使用 + +add = lambda x, y: x + y +print(add(1, 2)) + +square = lambda x: x**2 +print(square(2)) + +# 应用 +# 排序 +words = ["apple", "banana", "cherry", "date", "elderberry"] +words.sort(key=lambda x: len(x)) +print(words) + +# 按字符创长度降序拍 +words = ["apple", "banana", "cherry", "date", "elderberry"] +words.sort(key=lambda x: len(x), reverse=True) +print(words) + +students = [ + {"name": "Alice", "age": 20, "grade": 85}, + {"name": "Bob", "age": 19, "grade": 92}, + {"name": "Charlie", "age": 21, "grade": 78}, +] +# 按年龄排序 +students_by_age = sorted(students, key=lambda x: x["age"]) +print(students_by_age) +# 按成绩排序 +students_by_grade = sorted(students, key=lambda x: x["grade"], reverse=True) +print(students_by_grade) + + +# 在列表中使用lambda +numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +squared_numbers = [(lambda x: x**2)(item) for item in numbers] +print(squared_numbers) + +# 进行条件过滤 +large_numbers = [num for num in numbers if (lambda x: x > 5)(num)] +print(large_numbers) + +# 转大写 +texts = ["hello", "world", "python", "programming"] +upper_texts = [(lambda x: x.upper())(w) for w in texts] +print(upper_texts) diff --git a/20-24/lianxi-append.py b/20-24/lianxi-append.py new file mode 100644 index 0000000..83f6aeb --- /dev/null +++ b/20-24/lianxi-append.py @@ -0,0 +1,73 @@ +# 请详细说明它们的基本用法、区别、性能特点以及应用场景 + +# append、insert和extend都是Python列表操作方法,但它们有以下主要区别: + +# append:在列表末尾添加单个元素 +# insert:在列表指定位置插入单个元素 +# extend:将另一个可迭代对象的所有元素添加到列表末尾 + +# **都没有返回值,直接修改元数据 + +my_list = [1, 2, 3] + +my_list.append(4) +print(my_list) + + +# insert方法 +# 功能描述: insert方法用于在列表的指定位置插入一个元素,需要两个参数:插入位置的索引和要插入的元 +my_list = [1, 2, 3] +my_list.insert(2, "a") +print(my_list) +# 插到末尾 +my_list.insert(len(my_list), ["end"]) +print(my_list) + + +# 在有序列表中插入新元素并保持顺序 +sorted_list = [1, 3, 5, 7, 9] +new_number = 10 + +# 寻找合适的位置 +insert_index = 0 +for index, item in enumerate(sorted_list): + if item > new_number: + insert_index = index + break + else: + insert_index = len(sorted_list) + +sorted_list.insert(insert_index, new_number) +print(sorted_list) + + +# extend方法 +# 功能描述: extend方法用于将另一个可迭代对象(如列表、元组、字符串等)的所有元素逐个添加到当前列表的末尾。 + +my_list = [1, 2, 3] +my_list.extend([4, 5]) + +my_list.extend((1, 2)) +my_list.extend("str") +print(my_list) # [1, 2, 3, 4, 5, 1, 2, 's', 't', 'r'] + +# 应用 + +# 合并多个列表 +list1 = [1, 2, 3] +list2 = [4, 5, 6] +list3 = [7, 8, 9] + +new_list = [] +new_list.extend(list1) +new_list.extend(list2) +new_list.extend(list3) +print(new_list) + +# 处理嵌套数据结构 +nested_lists = [[1, 2], [3, 4], [5, [6]]] +flattened = [] +for arr in nested_lists: + flattened.extend(arr) + +print(flattened) # 只能展开双层,如果三层就不行了 [1, 2, 3, 4, 5, [6]] diff --git a/20-24/lianxi-enumerate.py b/20-24/lianxi-enumerate.py new file mode 100644 index 0000000..93ef734 --- /dev/null +++ b/20-24/lianxi-enumerate.py @@ -0,0 +1,87 @@ +# enumerate()函数的基本概念 +# enumerate()是Python的内置函数,用于将一个可迭代对象(如列表、元组、字符串等)组合成一个带索引的序列。 它返回一个枚举对象,该对象包含索引和对应的值,使得我们可以在循环中同时获取元素的索引和值。 + +# enumerate()函数的主要作用是解决在遍历可迭代对象时需要同时获取索引和值的常见需求,避免手动维护索引计数器。 + +# 数组结合 +items = ["苹果", "香蕉", "橙子", "葡萄"] +for index, val in enumerate(items): + print(f"{index}:{val}") + +# 字符串 +text = "Hello" +for index, s in enumerate(text): + print(f"{index}:{s}") + +# 元组 +coordinates = [(10, 20), (30, 40), (50, 60), (70, 80)] + +for index, (x, y) in enumerate(coordinates): + print(f"{index}:x-{x}y-{y}") + + +scores = {"数学": 95, "英语": 88, "物理": 92, "化学": 90} + +for index, (key, val) in enumerate(scores.items()): + print(f"{index}:{key}:{val}") + + +# 与其他内置函数结合 + +# zip() +names = ["张三", "李四", "王五"] +ages = [25, 30, 28] +cities = ["北京", "上海", "广州"] + +for index, (name, ages, cities) in enumerate(zip(names, ages, cities)): + print(f"{index}:name:{name},age:{ages},cities:{cities}") + + +# 与filter()函数结合使用 +# 过滤偶数 +list_arr = [1, 2, 3, 4, 5] +new_list = filter(lambda x: x % 2 == 0, list_arr) +for index, val in enumerate(new_list): + print(f"{index}:{val}") + + +# 与map()函数结合使用 +words = ["hello", "world", "python", "programming"] +upper_words = map(lambda s: s.upper(), words) +# print(list(upper_words)) + +for index, val in enumerate(upper_words): + print(f"{index}:{val}") + + +# 场景 +# 创建带索引的字典 +items = ["苹果", "香蕉", "橙子", "葡萄"] +indexed_dict = {index: item for index, item in enumerate(items)} +print(indexed_dict) + +for key, val in indexed_dict.items(): + print(f"{key}:{val}") + +# 查找元素的位置 + + +def find_all_potions(lst, target): + position = [index for index, val in enumerate(lst) if val == target] + return position + + +fruits = ["苹果", "香蕉", "橙子", "葡萄", "香蕉", "苹果"] +banana_positions = find_all_potions(fruits, "香蕉") +print(banana_positions) + + +# 条件计数 +scores = [85, 92, 78, 96, 88, 91, 87, 94] + +filter_scores = [] +for i, scorce in enumerate(scores): + if scorce > 90: + filter_scores.append({i: scorce}) + +print(filter_scores) diff --git a/20-24/lianxi-error.py b/20-24/lianxi-error.py new file mode 100644 index 0000000..4cc09d4 --- /dev/null +++ b/20-24/lianxi-error.py @@ -0,0 +1,11 @@ +my_dict = {"name": "Alice", "age": 25} + +# try: +# print(my_dict["abc"]) +# except KeyError: +# print("错误,访问的键不存在") +try: + print(my_dict["abc"]) +except Exception as e: + print(type(e)) # 打印异常的类型 + print(str(e)) # 打印异常的错误信息 diff --git a/20-24/lianxi-fusuoyin.py b/20-24/lianxi-fusuoyin.py new file mode 100644 index 0000000..91cf18e --- /dev/null +++ b/20-24/lianxi-fusuoyin.py @@ -0,0 +1,89 @@ +# Python的负索引是一种用于从序列(如列表、元组、字符串等)末尾倒数访问元素的方式。负索引从 -1 开始,表示序列的最后一个元素;-2 表示倒数第二个元素,以此类推。它使得我们更方便地访问序列末尾的元素,而不需要手动计算序列的长度。 + + +# 定义一个列表用于演示 +data = ["A", "B", "C", "D", "E", "F", "G"] + +# for i in range(len(data)): +# print(f"data[{i}] = {data[i]}") + +# 负索引 +for i in range(-1, -len(data) - 1, -1): + print(f"data[{i}]={data[i]}") + + +# 应用 +# 使用len和负索引 +items = ["apple", "banana", "cherry", "date", "elderberry"] +for i in range(-1, -len(items) - 1, -1): + print(f"{i}:{items[i]}") + +# 使用reversed +# 翻转列表 +for item in reversed(items): + print(item) + +# 使用切片 +reversed_items = items[::-1] +print(reversed_items) + + +# 反向遍历 +reversed_arr = [] +for index, item in enumerate(items): + last_index = len(items) - 1 - index + reversed_arr.append(items[last_index]) + # print(last_index) + print(f"{items[last_index]}") + +print("\n=== 反向遍历 ===") +print(reversed_arr) + +# 在算法中的应用 + +# 判断是否是回文数 + + +def is_palindrome(text=""): + text = text.lower().replace(" ", "") + length = len(text) // 2 + for i in range(length): + if text[i] != text[-(i + 1)]: + return False + return True + + +test_strings = ["racecar", "hello", "A man a plan a canal Panama", "python"] + +for s in test_strings: + result = is_palindrome(s) + print(f"{s}:{result}") + + +# 使用负索引实现数组旋转 +# 在实际算法开发中,负索引可用来优雅地解决列表、字符串、数组等序列相关的问题。 +def rotate_array(arr, k): + """ + 将数组向右旋转k个位置 + 例如: [1, 2, 3, 4, 5] 右旋1位 -> [5, 1, 2, 3, 4] + """ + k = k % len(arr) + return arr[-k:] + arr[:-k] + + +print("\n=== 数组旋转演示 ===") +test_array = [1, 2, 3, 4, 5] +for k in [1, 2, 3]: + rotate = rotate_array(test_array, k) + print(f"向右旋转{k}位:{rotate}") + +# arr[-k:] 取出最后k个元素(右侧) +# arr[:-k] 取出前面剩余的元素(左侧) +# 拼接即可得到右旋后的新数组 + +# +path = "/home/user/documents/file.txt" +extension = path.split("/")[-1] +print(extension) +abc = extension.split(".")[-1] +print(abc) diff --git a/20-24/lianxi-guanxiyunsuanfu.py b/20-24/lianxi-guanxiyunsuanfu.py new file mode 100644 index 0000000..784afed --- /dev/null +++ b/20-24/lianxi-guanxiyunsuanfu.py @@ -0,0 +1,36 @@ +# +def validate_user_input(age, sorce, name): + error = [] + if age < 18 or age > 65: + error.append("年龄必须在18到65之间") + if not (60 < sorce <= 100): + error.append("分数必须在60到100之间") + if not (2 < len(name) <= 20): + error.append("姓名长度必须在2~20之间") + if error: + return f"验证失败{','.join(error)}" + else: + return "验证成功" + + +test_cases = [ + (25, 85, "Alice"), + (17, 85, "Alice"), + (25, 105, "Alice"), + (25, 85, "A"), + (25, 85, "A" * 25), +] + +for age, sorce, name in test_cases: + result = validate_user_input(age, sorce, name) + print(result) + + +# 条件筛选 +def filter_data(datalist, min_val, max_val): + return [x for x in datalist if min_val < x < max_val] + + +test_data = [1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50] +filter_data = filter_data(test_data, 0, 20) +print(filter_data) diff --git a/20-24/lianxi-listortuple.py b/20-24/lianxi-listortuple.py new file mode 100644 index 0000000..528c88e --- /dev/null +++ b/20-24/lianxi-listortuple.py @@ -0,0 +1,63 @@ +# 列表转元组 +original_list = [1, 2, 3, 4, 5] +converted_tuple = tuple(original_list) +print(f"原始列表: {original_list}, 类型: {type(original_list)}") +print(f"转换后元组: {converted_tuple}, 类型: {type(converted_tuple)}") + +# 元组转列表 +original_tuple = ("a", "b", "c", "d", "e") +converted_list = list(original_tuple) +print(f"原始元组: {original_tuple}, 类型: {type(original_tuple)}") +print(f"转换后列表: {converted_list}, 类型: {type(converted_list)}") + +# 字符串转列表和元组 +text = "Python" +text_list = list(text) +text_tuple = tuple(text) +print(f"原始字符串: {text}") +print(f"转换为列表: {text_list}") +print(f"转换为元组: {text_tuple}") + +# 列表推导式创建 +squares_list = [x**2 for x in range(5)] +squares_tuple = tuple(x**2 for x in range(5)) +print(f"列表推导式: {squares_list}") +print(f"元组推导式: {squares_tuple}") + + +nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9], 10] +abc = tuple(nested_list) +print(abc) + +mixed_structure = [(1, 2), [3, 4], (5, 6)] +aaa = tuple(mixed_structure) +print(aaa) + + +def get_statistics(data): + return min(data), max(data), sum(data), len(data) + + +data = [1, 2, 3, 4, 5] +min_val, max_val, sum_val, len_val = get_statistics(data) +print(min_val, max_val, sum_val, len_val) + + +nested_data = [((1, 2), (3, 4)), ((5, 6), (7, 8))] + +# 在循环中解封装嵌套结构 +print(f"\n嵌套结构:") +for (a, b), (c, d) in nested_data: + # 打印每个嵌套结构 + print(f"第一组: ({a}, {b}), 第二组: ({c}, {d})") + + +data = (1, 2, 3, 4, 5) + +a, *middle, c = data +print(middle) # [2, 3, 4] + + +squares = {x: x**2 for x in range(1, 6)} +# 打印字典推导式创建的字典 +print("字典推导式创建的字典:", squares) diff --git a/20-24/lianxi-read.py b/20-24/lianxi-read.py new file mode 100644 index 0000000..0266ed6 --- /dev/null +++ b/20-24/lianxi-read.py @@ -0,0 +1,68 @@ +# Python提供了三种主要的文件读取方法,每种方法都有其特定的用途和特点: + +# read():一次性读取整个文件内容 +# readline():逐行读取文件,每次读取一行 +# readlines():一次性读取所有行,返回列表 + +# 特性 read() readline() readlines() +# 读取方式 一次性读取全部内容 逐行读取 一次性读取所有行 +# 返回类型 字符串 字符串 列表(每行一个元素) +# 内存使用 高(整个文件) 低(单行) 高(所有行) +# 适用场景 小文件、配置文件 大文件、逐行处理 需要所有行的场景 +# 文件指针 移动到文件末尾 移动到下一行 移动到文件末尾 + + +# read()方法 +# 一次读取整个文件内容 + +# 创建测试文件内容,包含多行文本 +test_content = """第一行:Python文件读取 +第二行:read()方法示例 +第三行:一次性读取全部内容 +第四行:适合小文件处理 +第五行:返回字符串类型""" + +with open("test-file.txt", "w", encoding="utf-8") as f: + f.write(test_content) + +# 读取整个文件 +with open("test-file.txt", "r", encoding="utf-8") as f: + content = f.read() + print(content) + print(f"文件长度{len(content)}") + print(f"指针位置{f.tell()}") + + +# readline() 逐行读取 + +with open("test-file.txt", "r", encoding="utf-8") as f: + line_num = 1 + while True: + line = f.readline() + if not line: + break + print(f"读取第{line_num}行,内容{line}") + line_num += 1 + +# 重置文件指针并演示指定大小读取 +print("=== readline() 指定大小读取 ===") + +with open("test-file.txt", "r", encoding="utf-8") as f: + partial_line = f.readline(10) + print(f"读取前10个字符: {repr(partial_line)}") + print(f"剩余内容: {repr(f.readline())}") + + +# readlines()方法 +# 一次读取所有航,返回列表 + +with open("test-file.txt", "r", encoding="utf-8") as f: + lines = f.readlines() + print(f"打印数据类型{type(lines)}") + print(f"打印数据长度{len(lines)}") + print(lines) + + # + for index, line in enumerate(lines, 1): + clear_line = line.strip() # 去除收尾空格以及换行符 + print(f"第{index}行:{repr(clear_line)}") diff --git a/20-24/lianxi-remove.py b/20-24/lianxi-remove.py new file mode 100644 index 0000000..661a73f --- /dev/null +++ b/20-24/lianxi-remove.py @@ -0,0 +1,65 @@ +# remove、del和pop都是用于从列表中删除元素的,但它们在用法、功能和行为上有所不同: + +# remove(item): + +# 功能:根据值来删除列表中的第一个匹配项 +# 返回值:无返回值(None) +# 异常:如果列表中不存在指定的item,会抛出ValueError +# del语句: + +# 功能:可以删除列表中的一个或多个元素(通过索引或切片),也可以删除整个列表,甚至删除变量本身 +# 语法:del list[index](删除单个元素)或del list[start:end](删除切片) +# 返回值:无返回值 +# 异常:如果指定的索引或切片范围超出列表边界,会抛出IndexError +# pop([index]): + +# 功能:默认删除并返回列表中的最后一个元素。如果指定了index,则删除并返回该索引处的元素 +# 返回值:返回被删除的元素 +# 异常:如果列表为空或指定的index不存在,会抛出IndexError + + +# 应用场景 +# 定义用于检查括号是否匹配的函数 + +# 创建一个简单的栈 + + +class SimpleStack: + def __init__(self): + self.items = [] + + def push(self, item): + self.items.append(item) + + def pop(self): + if not self.is_empth(): + return self.items.pop() + else: + return None + + def is_empth(self): + return len(self.items) == 0 + + def peek(self): + if not self.is_empth(): + return self.items[:-1] + else: + return None + + +def is_balanced_parentheses(expression): + stack = SimpleStack() + pairs = {"(": ")", "{": "}", "[": "]"} + + for char in expression: + if pairs.get(char): + stack.push(char) + elif stack.is_empth() or pairs[stack.pop()] != char: + return False + return stack.is_empth() + + +test_expressions = ["()", "()[]{}", "(]", "([)]", "{[]}"] +for expr in test_expressions: + # 输出每一个表达式的匹配结果 + print(f"'{expr}' 是否平衡: {is_balanced_parentheses(expr)}") diff --git a/20-24/lianxi-replace.py b/20-24/lianxi-replace.py new file mode 100644 index 0000000..be4f027 --- /dev/null +++ b/20-24/lianxi-replace.py @@ -0,0 +1,66 @@ +def clean_user_input(user_input): + replacements = { + " ": " ", # 将双空格替换为单空格 + "\t": " ", # 将制表符替换为空格 + "\n": " ", # 将换行符替换为空格 + "&": "and", # 将&符号替换为and + "@": "at", # 将@符号替换为at + } + + # 替换 + cleaned_input = user_input + for old, new in replacements.items(): + cleaned_input = cleaned_input.replace(old, new) + # 去除收尾空格 + cleaned_input = cleaned_input.strip() + return cleaned_input + + +dirty_input = "Hello world\t\n&@test" +clean_result = clean_user_input(dirty_input) +print("清洗前:", repr(dirty_input)) +print("清洗后:", repr(clean_result)) + + +def replace_email_template(template, user_data): + for key, val in user_data.items(): + template = template.replace(f"{{{key}}}", val) + + return template + + +# 定义邮件模板 +email_template = """ +Dear {name}, + +Thank you for your order #{order_id}. +Your total amount is ${amount}. + +Best regards, +Customer Service +""" + +# 定义用户数据 +user_data = {"name": "Alice", "order_id": "12345", "amount": "99.99"} + +final_email = replace_email_template(email_template, user_data) +print(final_email) + + +email_template = """ +Dear {name}, + +Thank you for your order #{order_id}. +Your total amount is ${amount}. + +Best regards, +Customer Service +""" + +# 定义用户数据 +user_data = {"name": "Alice", "order_id": "12345", "amount": "99.99"} + +# 使用 `format()` 方法替换模板中的占位符 +email = email_template.format(**user_data) + +print(email) diff --git a/20-24/lianxi-reversed.py b/20-24/lianxi-reversed.py new file mode 100644 index 0000000..120bed2 --- /dev/null +++ b/20-24/lianxi-reversed.py @@ -0,0 +1,41 @@ +# 翻转字符串 +# 推荐方式 +# 切片 +original_string = "hello" +reversed_string = original_string[::-1] +# print(reversed_string) + +# 使用reversed 和 join结合 + + +def reverse_with_list(text): + char_list = list(text) + char_list.reverse() + return "".join(char_list) + + +original_string = "hello" + +print(reverse_with_list(original_string)) + + +# for循环 +original_string = "hello" +reverse_string = "" +for char in original_string: + reverse_string = char + reverse_string +print(reverse_string) + + +# 递归 +def reverse_string_tail(s, result=""): + if len(s) == 0: + return result + else: + return reverse_string_tail(s[1:], s[0] + result) + + +text_string = "Python" +print(reverse_string_tail(text_string)) + +print("7" < "8") diff --git a/20-24/lianxi-sanyuan.py b/20-24/lianxi-sanyuan.py new file mode 100644 index 0000000..480a8ff --- /dev/null +++ b/20-24/lianxi-sanyuan.py @@ -0,0 +1,67 @@ +# 三元运算符 + +x = 10 +result = "正数" if x > 0 else "负数" +# print(result) + + +# 根据用户输入设置默认值 + + +# def get_user_input(): +# user_input = input("请输入数值1~3:") +# preference = user_input if int(user_input) in [1, 2, 3] else 1 +# return preference + + +# preference = get_user_input() +# print(preference) + + +# 处理空值 + +user_dict = [{"name": "小明", "age": 18, "id": 1}, {"name": "小红", "age": 20, "id": 2}] + +filter_user = list(filter(lambda user: user["id"] == 1, user_dict)) +# print(filter_user) + +# 列表推导式 + +numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +processed_numbers = [str(x) if x % 2 == 0 else x for x in numbers] +print(processed_numbers) + +scores = [85, 92, 78, 96, 88, 91, 87, 94] +grade_list = ["优秀" if s >= 90 else "良好" for s in scores] +print(grade_list) + +# 处理字符串列表 +words = ["hello", "world", "python", "programming"] +# 将长度大于5的单词转换为大写,其他保持原样 +processed_word = [w.upper() if len(w) > 5 else w for w in words] +print(processed_word) + + +def get_user_role(user_type): + return "管理员" if user_type == "admin" else "普通用户" + + +def calculate_discount(amount, is_vip): + # 计算折扣 + # 如果是VIP用户且金额大于1000,则打8折 + # 否则,不打折 + discoint_rate = 0.8 if amount > 1000 and is_vip else 1 + return amount * discoint_rate + + +result = calculate_discount(100, True) +print(result) + + +def format_phone_number(phone): + return f"{phone[:3]}-{phone[3:7]}-{phone[7:]}" if len(phone) == 11 else phone + + +print(f"格式化电话号码:{format_phone_number('13812345678')}") +print(f"格式化电话号码:{format_phone_number('1234567')}") diff --git a/20-24/lianxi-switch.py b/20-24/lianxi-switch.py new file mode 100644 index 0000000..0559e9e --- /dev/null +++ b/20-24/lianxi-switch.py @@ -0,0 +1,119 @@ +# Python没有原生的switch-case语句,但可以通过以下几种方式来实现类似的功能: + +# if-elif-else结构:最直接的方法,适合简单的条件判断 +# 字典映射:推荐的方法,利用字典的键值对映射实现高效的条件分支 +# 函数字典:在字典中存储函数对象,实现复杂的逻辑处理 +# Python 3.10+ match语句:现代Python提供的模式匹配语法 + + +# 字典映射 +def switch_dict(case): + switcher = { + "A": "case A", + "B": "case B", + "C": "case C", + } + return switcher.get(case, "Defaule Case") + + +result = switch_dict("A") +print(result) # case A +result = switch_dict("D") +print(result) # Defaule Case + + +# 使用函数字典 +def case_a(): + return "Action for case A" + + +def case_b(): + return "Action for case B" + + +def case_c(): + return "Action for case C" + + +def case_default(): + return "Default action" + + +def switch_funtion_dice(case): + switer = {"A": case_a, "B": case_b, "C": case_c} + fn = switer.get(case, case_default) + return fn() + + +result = switch_funtion_dice("A") +print(result) +result = switch_funtion_dice("F") +print(result) + + +# 自 Python 3.10 起,官方引入了结构化匹配(match 语句),可以原生实现类似 switch 的多分支选择功能。match 让代码更加优雅、可读性更强,尤其适用于分支较多、需要解构或复杂条件匹配的场景。 + + +def switch_match(case): + """ + 使用 Python 3.10+ 的 match 语句实现 switch 功能 + 这是最现代和强大的方法 + """ + match case: + case "A": + return "Case A" + case "B": + return "Case B" + case "C": + return "Case C" + case _: + return "Default case" + + +result = switch_match("A") +print(result) +result = switch_match("F") +print(result) # Default case + + +# 数值范围匹配 +def grade_evaluator(sorce): + grade_map = { + range(90, 101): "A", + range(80, 90): "B", + range(70, 80): "C", + range(60, 70): "D", + } + for score_range, grade in grade_map.items(): + if sorce in score_range: + return grade + + return "F" + + +# 测试成绩评估 +scores = [ + {"scorce": 95}, + {"scorce": 85}, + {"scorce": 75}, + {"scorce": 65}, + {"scorce": 55}, +] + +for item in scores: + grade = grade_evaluator(item["scorce"]) + item["grade"] = grade + +print(scores) + + +def greet(name, msg="Hello"): + print(f"{msg}, {name}!") + + +greet("Alice") # 输出:Hello, Alice! +greet("Bob", "Hi") # 输出:Hi, Bob! + + +num_enough = 10 +print(num_enough is False) \ No newline at end of file diff --git a/20-24/output.txt b/20-24/output.txt new file mode 100644 index 0000000..e69de29 diff --git a/test-uv/.gitignore b/test-uv/.gitignore new file mode 100644 index 0000000..505a3b1 --- /dev/null +++ b/test-uv/.gitignore @@ -0,0 +1,10 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv diff --git a/test-uv/.python-version b/test-uv/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/test-uv/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/test-uv/README.md b/test-uv/README.md new file mode 100644 index 0000000..e69de29 diff --git a/test-uv/main.py b/test-uv/main.py new file mode 100644 index 0000000..78a4563 --- /dev/null +++ b/test-uv/main.py @@ -0,0 +1,32 @@ +# 导入 FastAPI 框架,用于构建 Web API +from fastapi import FastAPI + +# 导入 requests 库,用于发送 HTTP 请求 +import requests + +# 导入 uvicorn,用于作为 ASGI 服务器启动应用 +import uvicorn + +# 创建fastapi应用实例 +app = FastAPI() + + +# 定义根路由,当访问"/"时触发 +@app.get("/") +# 处理根路径请求的函数,返回一个消息 +def read_root(): + return {"message": "Hello wordl"} + + +# 定义/external路由,当访问"/external"时触发 +@app.get("/external") +# 处理/external路径请求的函数,从外部获取数据 +def get_external_data(): + # 发送GET请求到 https://www.example.com + response = requests.get("https://www.example.com") + # 返回请求的状态码 + return {"status": response.status_code} + + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port="8000") diff --git a/test-uv/pyproject.toml b/test-uv/pyproject.toml new file mode 100644 index 0000000..d42e30e --- /dev/null +++ b/test-uv/pyproject.toml @@ -0,0 +1,17 @@ +[project] +name = "test-uv" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "fastapi>=0.121.2", + "requests>=2.32.5", + "uvicorn>=0.38.0", +] + +[dependency-groups] +dev = [ + "httpx>=0.28.1", + "pytest>=9.0.1", +] diff --git a/test-uv/test_main.py b/test-uv/test_main.py new file mode 100644 index 0000000..034f765 --- /dev/null +++ b/test-uv/test_main.py @@ -0,0 +1,37 @@ +# 导入FastAPI的TestClient,用于测试FastAPI +# from fastapi.testclient import TestClient + +# # 从main模块导入app对象 +# from main import app + +# # 创建TestClient实例,传入FastAPI应用 +# client = TestClient(app) + + +# def test_read_root(): +# # 使用客户端发起请求 +# response = client.get("/") +# # 断言返回200状态码,表示请求成功 +# assert response.status_code == 200 +# # 断言返回的json数据 +# assert response.json() == {"message": "Hello World"} + + +# 导入FastAPI的TestClient,用于测试FastAPI应用 +from fastapi.testclient import TestClient + +# 从main模块导入app对象(FastAPI实例) +from main import app + +# 创建TestClient实例,传入FastAPI应用 +client = TestClient(app) + + +# 定义测试根路径的函数 +def test_read_root(): + # 使用测试客户端发起GET请求到根路径 + response = client.get("/") + # 断言返回状态码为200,表示请求成功 + assert response.status_code == 200 + # 断言返回的JSON数据为{"message": "Hello World"} + assert response.json() == {"message": "Hello World"} diff --git a/test-uv/uv.lock b/test-uv/uv.lock new file mode 100644 index 0000000..48c41b3 --- /dev/null +++ b/test-uv/uv.lock @@ -0,0 +1,430 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "fastapi" +version = "0.121.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/48/f08f264da34cf160db82c62ffb335e838b1fc16cbcc905f474c7d4c815db/fastapi-0.121.2.tar.gz", hash = "sha256:ca8e932b2b823ec1721c641e3669472c855ad9564a2854c9899d904c2848b8b9", size = 342944, upload-time = "2025-11-13T17:05:54.692Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/23/dfb161e91db7c92727db505dc72a384ee79681fe0603f706f9f9f52c2901/fastapi-0.121.2-py3-none-any.whl", hash = "sha256:f2d80b49a86a846b70cc3a03eb5ea6ad2939298bf6a7fe377aa9cd3dd079d358", size = 109201, upload-time = "2025-11-13T17:05:52.718Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pydantic" +version = "2.12.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/ad/a17bc283d7d81837c061c49e3eaa27a45991759a1b7eae1031921c6bd924/pydantic-2.12.4.tar.gz", hash = "sha256:0f8cb9555000a4b5b617f66bfd2566264c4984b27589d3b845685983e8ea85ac", size = 821038, upload-time = "2025-11-05T10:50:08.59Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/2f/e68750da9b04856e2a7ec56fc6f034a5a79775e9b9a81882252789873798/pydantic-2.12.4-py3-none-any.whl", hash = "sha256:92d3d202a745d46f9be6df459ac5a064fdaa3c1c4cd8adcfa332ccf3c05f871e", size = 463400, upload-time = "2025-11-05T10:50:06.732Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "starlette" +version = "0.49.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/1a/608df0b10b53b0beb96a37854ee05864d182ddd4b1156a22f1ad3860425a/starlette-0.49.3.tar.gz", hash = "sha256:1c14546f299b5901a1ea0e34410575bc33bbd741377a10484a54445588d00284", size = 2655031, upload-time = "2025-11-01T15:12:26.13Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/e0/021c772d6a662f43b63044ab481dc6ac7592447605b5b35a957785363122/starlette-0.49.3-py3-none-any.whl", hash = "sha256:b579b99715fdc2980cf88c8ec96d3bf1ce16f5a8051a7c2b84ef9b1cdecaea2f", size = 74340, upload-time = "2025-11-01T15:12:24.387Z" }, +] + +[[package]] +name = "test-uv" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "fastapi" }, + { name = "requests" }, + { name = "uvicorn" }, +] + +[package.dev-dependencies] +dev = [ + { name = "httpx" }, + { name = "pytest" }, +] + +[package.metadata] +requires-dist = [ + { name = "fastapi", specifier = ">=0.121.2" }, + { name = "requests", specifier = ">=2.32.5" }, + { name = "uvicorn", specifier = ">=0.38.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "httpx", specifier = ">=0.28.1" }, + { name = "pytest", specifier = ">=9.0.1" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/f06b84e2697fef4688ca63bdb2fdf113ca0a3be33f94488f2cadb690b0cf/uvicorn-0.38.0.tar.gz", hash = "sha256:fd97093bdd120a2609fc0d3afe931d4d4ad688b6e75f0f929fde1bc36fe0e91d", size = 80605, upload-time = "2025-10-18T13:46:44.63Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/d9/d88e73ca598f4f6ff671fb5fde8a32925c2e08a637303a1d12883c7305fa/uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02", size = 68109, upload-time = "2025-10-18T13:46:42.958Z" }, +]