├── README.md ├── 代码 ├── Area.py ├── BranchAttr.py ├── Counter.py ├── LoopAttr.py ├── MyDict.py ├── Pocker.py ├── Point2D.py ├── Point2DFixed.py ├── Point2D_data_descriptor.py ├── Point2D_extended.py ├── Point2D_new_class.py ├── Point2D_type.py ├── Rune.py ├── abc1.py ├── abc2.py ├── abc3.py ├── abc4.py ├── annotation1.py ├── annotation2.py ├── annotation3.py ├── annotation3.pyi ├── argv.py ├── arithmetic_calculator.py ├── async_comprehension.py ├── async_context_manager.py ├── async_debug1.py ├── async_debug2.py ├── async_generator.py ├── async_iterator.py ├── boolean_calculator.py ├── bubble_sort.py ├── cache.py ├── calculator_factory.py ├── class_decorator1.py ├── class_decorator2.py ├── clock_descriptor.py ├── closure1.py ├── closure2.py ├── context_manager.py ├── coroutine1.py ├── coroutine10.py ├── coroutine11.py ├── coroutine12.py ├── coroutine13.py ├── coroutine14.py ├── coroutine15.py ├── coroutine16.py ├── coroutine17.py ├── coroutine18.py ├── coroutine19.py ├── coroutine2.py ├── coroutine20.py ├── coroutine21.py ├── coroutine22.py ├── coroutine23.py ├── coroutine24.py ├── coroutine25.py ├── coroutine26.py ├── coroutine27.py ├── coroutine28.py ├── coroutine29.py ├── coroutine3.py ├── coroutine30.py ├── coroutine31.py ├── coroutine32.py ├── coroutine33.py ├── coroutine34.py ├── coroutine35.py ├── coroutine36.py ├── coroutine37.py ├── coroutine38.py ├── coroutine39.py ├── coroutine4.py ├── coroutine40.py ├── coroutine41.py ├── coroutine42.py ├── coroutine43.py ├── coroutine44.py ├── coroutine45.py ├── coroutine46.py ├── coroutine5.py ├── coroutine6.py ├── coroutine7.py ├── coroutine8.py ├── coroutine9.py ├── debug1.py ├── debug2.py ├── debug3.py ├── debug4.py ├── demo.py ├── demo │ ├── __init__.py │ ├── __main__.py │ ├── factorial_sequence.py │ └── main.py ├── dir1 │ ├── __init__.py │ ├── a.py │ ├── b.py │ ├── dir2 │ │ ├── __init__.py │ │ ├── c.py │ │ └── dir3 │ │ │ ├── __init__.py │ │ │ └── d.py │ └── dir4 │ │ ├── __init__.py │ │ ├── dir5 │ │ └── f.py │ │ └── e.py ├── docstring.py ├── encapsulation1.py ├── encapsulation2.py ├── encapsulation3.py ├── encapsulation4.py ├── encapsulation5.py ├── eval.py ├── exception1.py ├── exception10.py ├── exception11.py ├── exception12.py ├── exception2.py ├── exception3.py ├── exception4.py ├── exception5.py ├── exception6.py ├── exception7.py ├── exception8.py ├── exception9.py ├── exception_group.py ├── exec.py ├── factorial1.py ├── factorial2.py ├── flags.py ├── function_decorator1.py ├── function_decorator2.py ├── function_decorator3.py ├── function_decorator4.py ├── function_decorator5.py ├── generator1.py ├── generator2.py ├── generator3.py ├── generator4.py ├── generator5.py ├── generator6.py ├── integer_adder.py ├── interactivehook.py ├── is_finalizing.py ├── iterate1.py ├── iterate2.py ├── iterate3.py ├── iterate4.py ├── iterate5.py ├── iterate6.py ├── iterate7.py ├── lru_cache.py ├── match1.py ├── match10.py ├── match11.py ├── match12.py ├── match13.py ├── match14.py ├── match15.py ├── match16.py ├── match17.py ├── match18.py ├── match19.py ├── match2.py ├── match3.py ├── match4.py ├── match5.py ├── match6.py ├── match7.py ├── match8.py ├── match9.py ├── metaclass1.py ├── metaclass2.py ├── metaclass3.py ├── metaclass4.py ├── metaclass5.py ├── metaclass6.py ├── mixed_accumulator.py ├── mixed_calculator.py ├── module1.py ├── module2.py ├── module3.py ├── number_sign_1.py ├── number_sign_2.py ├── number_sign_3.py ├── number_sign_game_1.py ├── number_sign_game_2.py ├── number_sign_game_3.py ├── number_sign_game_4.py ├── polymorphism1.py ├── polymorphism2.py ├── profile1.py ├── profile2.py ├── profile3.py ├── profile4.py ├── quirk_class_definition.py ├── raise1.py ├── raise2.py ├── raise3.py ├── raise4.py ├── scope1.py ├── scope2.py ├── scope3.py ├── super.py ├── typing1.pyi ├── typing10.pyi ├── typing11.py ├── typing12.pyi ├── typing13.py ├── typing14.pyi ├── typing15.py ├── typing16.py ├── typing17.py ├── typing18.pyi ├── typing19.py ├── typing2.py ├── typing20.py ├── typing21.py ├── typing22.py ├── typing3.pyi ├── typing4.py ├── typing5.pyi ├── typing6.py ├── typing7.py ├── typing8.pyi ├── typing9.py ├── warnings1.py ├── warnings2.py ├── warnings3.py ├── warnings4.py ├── warnings5.py ├── weakref1.py ├── weakref2.py ├── weakref3.py ├── weakref4.py └── weapons.py ├── 封面和扉页.pdf ├── 第10章. 字符串和二进制序列.pdf ├── 第11章. 容器.pdf ├── 第12章. 迭代.pdf ├── 第13章. 模式匹配.pdf ├── 第14章. 异步编程.pdf ├── 第15章. 高级话题.pdf ├── 第16章. 调试和分析.pdf ├── 第17章. 软件分发.pdf ├── 第1章. 你是否需要Python,以及如何掌握Python?.pdf ├── 第2章. 词法分析.pdf ├── 第3章. 数据模型.pdf ├── 第4章. 函数.pdf ├── 第5章. 类.pdf ├── 第6章. 模块与作用域.pdf ├── 第7章. Python的运行时服务.pdf ├── 第8章. 防御式编程.pdf ├── 第9章. 数字.pdf ├── 简介和目录.pdf ├── 附录 I. 在CentOS 9上安装Python 3.11.pdf ├── 附录 II. 魔术属性.pdf ├── 附录 III. 标准解释器类型.pdf ├── 附录 IV. 内置函数.pdf ├── 附录 V. 泛型具象.pdf ├── 附录 VI. setuptool.setup()的关键字.pdf └── 附录 VII. setup.cfg的键.pdf /README.md: -------------------------------------------------------------------------------- 1 | 这本书与其他关于Python编程的书的最大不同在于,它是目前唯一一本全面、系统地讨论了Python的所有语法的书。 2 | 3 | 正如它的名字——《Python官方手册解析:基于Python 3.11》——所示,这本书以Python 3.11的官方手册为基础,覆盖了官方手册中的所有语法点,以及Python标准库中的下列与Python语法密切相关的模块:abc,asyncio,builtins,collections.abc,ensurepip,functools,io,numbers,pdb,profile,site,sys,types,typing,venv,warnings,weakref。 4 | 5 | 这本书并不是语法点的简单罗列。我在写作本书时的参照物是《C Primer Plus》,因此本书的风格也与《C Primer Plus》接近,不仅介绍了每个语法点是什么,还探讨了它们背后的逻辑,分析了为什么要引入这个语法,以及这个语法的适用范围是什么。然而由于Python的语法比C要复杂得多,再加上本书针对每个语法点都给出了具体例子,所以本书也比《C Primer Plus》厚得多。 6 | 7 | 本书的目标读者群体是已经对编程有了感性认识(例如上过一门类似“编程导论”这样的课),想要彻底掌握一门编程语言,又不想深入了解计算机系统的底层细节的人。绝大部分不以商业级别的软件开发为最终目标的理工类专业人士,乃至需要分析大量数据的经管类专业人士,都符合这一标准。 8 | -------------------------------------------------------------------------------- /代码/Area.py: -------------------------------------------------------------------------------- 1 | class Area: 2 | #该类的实例只具有两个实例属性:长度和高度。 3 | def __init__(self, l, h): 4 | self.length = l 5 | self.height = h 6 | 7 | #添加了__getattr__使得访问该类的实例的任何其他属性时都返回面积,就好像面积是该类 8 | # 实例的默认属性值。 9 | def __getattr__(self, name): 10 | return self.length * self.height 11 | 12 | -------------------------------------------------------------------------------- /代码/BranchAttr.py: -------------------------------------------------------------------------------- 1 | from random import randrange 2 | 3 | 4 | class BranchAttr: 5 | #生成一个0~9之间的随机整数。 6 | n = randrange(0, 10) 7 | 8 | #当随机整数是0、1、2、3、4时定义star()属性。 9 | if n<5: 10 | def star(): 11 | return '*' 12 | #当随机整数是5、6、7、8、9时定义dollar()属性。 13 | else: 14 | def dollar(): 15 | return '$' 16 | 17 | #删除引用随机整数的标识符,避免它成为类的属性。 18 | del n 19 | 20 | -------------------------------------------------------------------------------- /代码/Counter.py: -------------------------------------------------------------------------------- 1 | #本脚本定义了一个代表计数器的类。 2 | class Counter: 3 | def __init__(self): 4 | self.n = 0 5 | 6 | #该属性实现计数,并在每次计数时执行指定的操作。 7 | def tik(self): 8 | self.n += 1 9 | return self.n 10 | 11 | #该属性重置计数器。 12 | def reset(self): 13 | self.n = 0 14 | -------------------------------------------------------------------------------- /代码/LoopAttr.py: -------------------------------------------------------------------------------- 1 | #通过标准输入获得一个正整数。 2 | n = input("请输入一个正整数:") 3 | n = int(n) 4 | if n < 1: 5 | n = 1 6 | 7 | 8 | class LoopAttr: 9 | #将n声明为全局变量,以避免它成为类的属性。 10 | global n 11 | 12 | #创建属性a1、a2、...、an。 13 | #分别将它们赋值1、2、...、n。 14 | while n > 0: 15 | exec('a'+str(n)+' = '+str(n)) 16 | n = n-1 17 | 18 | -------------------------------------------------------------------------------- /代码/MyDict.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | #该类继承了collections模块定义的UserDict类,使得自定义映射类型变得简单。 4 | class MyDict(collections.UserDict): 5 | def __init__(self, initialdata): 6 | self.data = collections.UserDict(initialdata) 7 | 8 | def __missing__(self, key): 9 | return "Unmatched key: " + str(key) 10 | 11 | -------------------------------------------------------------------------------- /代码/Pocker.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | #定义一个代表扑克牌的类。 4 | @functools.total_ordering 5 | class Pocker: 6 | #添加了如下实例属性: 7 | # suit:扑克牌的花色,用1~4分别表示黑桃、红桃、梅花和方块。 8 | # rank:扑克牌的位阶,用1~13分别表示A、2~10和J、Q、K。 9 | def __init__(self, suit, rank): 10 | self.suit = int(suit) 11 | if self.suit > 4: 12 | self.suit = 4 13 | if self.suit < 1: 14 | self.suit = 1 15 | self.rank = int(rank) 16 | if self.rank > 13: 17 | self.rank = 13 18 | if self.rank < 1: 19 | self.rank = 1 20 | 21 | #显示一张扑克的花色和位阶。 22 | def show(self): 23 | #识别花色。 24 | if self.suit == 1: 25 | s = 'Spade' 26 | elif self.suit == 2: 27 | s = 'Heart' 28 | elif self.suit == 3: 29 | s = 'Club' 30 | else: 31 | s = 'Diamond' 32 | #识别位阶。 33 | if self.rank == 1: 34 | s = s + ' A' 35 | elif self.rank == 11: 36 | s = s + ' J' 37 | elif self.rank == 12: 38 | s = s + ' Q' 39 | elif self.rank == 13: 40 | s = s + ' K' 41 | else: 42 | s = s + ' ' + str(self.rank) 43 | #输出结果。 44 | print(s) 45 | 46 | #两张扑克相等的规则是花色和位阶都相同。 47 | def __eq__(self, other): 48 | if self.suit == other.suit and self.rank == other.rank: 49 | return True 50 | else: 51 | return False 52 | 53 | #扑克排序的规则是先比较位阶再比较花色。 54 | def __lt__(self, other): 55 | srank = self.rank 56 | if srank == 1: 57 | srank = 14 58 | orank = other.rank 59 | if orank == 1: 60 | orank = 14 61 | if srank < orank: 62 | return True 63 | elif srank > orank: 64 | return False 65 | else: 66 | if self.suit <= other.suit: 67 | return False 68 | else: 69 | return True 70 | 71 | -------------------------------------------------------------------------------- /代码/Point2D.py: -------------------------------------------------------------------------------- 1 | class Point2D: 2 | #类属性dimension。 3 | dimension = 2 4 | 5 | #在初始化时设置了实例属性x和y。 6 | def __init__(self, x, y): 7 | self.x = x 8 | self.y = y 9 | 10 | #类属性move。 11 | def move(self, dx, dy): 12 | self.x += dx 13 | self.y += dy 14 | 15 | #类属性location。 16 | def location(self): 17 | print("(" + str(self.x) + ", " + str(self.y) + ")") 18 | 19 | -------------------------------------------------------------------------------- /代码/Point2DFixed.py: -------------------------------------------------------------------------------- 1 | class Point2DFixed: 2 | dimension = 2 3 | 4 | def __init__(self, x, y): 5 | self.x = x 6 | self.y = y 7 | 8 | def move(self, dx, dy): 9 | self.x += dx 10 | self.y += dy 11 | 12 | def location(self): 13 | print("(" + str(self.x) + "," + str(self.y) + ")") 14 | 15 | #通过__slots__指定实例属性。 16 | __slots__ = ("x", "y", "area") 17 | 18 | -------------------------------------------------------------------------------- /代码/Point2D_data_descriptor.py: -------------------------------------------------------------------------------- 1 | #该类是一个数据描述器。 2 | class Dimension: 3 | def __init__(self, value): 4 | self.value = int(value) 5 | 6 | def __get__(self, instance, owner=None): 7 | return self.value 8 | 9 | #仅当通过实例设置该描述器时会被调用。 10 | def __set__(self, instance, value): 11 | print("Instances cannot change the value of its class attributes.") 12 | return None 13 | 14 | #仅当通过实例删除该描述器时会被调用。 15 | def __delete__(self, instance): 16 | print("Instances cannot delete its class attributes.") 17 | return None 18 | 19 | 20 | class Point2D: 21 | #该属性引用一个数据描述器。 22 | dimension = Dimension(2) 23 | 24 | def __init__(self, x, y): 25 | self.x = x 26 | self.y = y 27 | 28 | def move(self, dx, dy): 29 | self.x += dx 30 | self.y += dy 31 | 32 | def location(self): 33 | print("(" + str(self.x) + ", " + str(self.y) + ")") 34 | 35 | -------------------------------------------------------------------------------- /代码/Point2D_extended.py: -------------------------------------------------------------------------------- 1 | class Point2D: 2 | dimension = 2 3 | 4 | def __init__(self, x, y): 5 | self.x = x 6 | self.y = y 7 | 8 | def move(self, dx, dy): 9 | self.x += dx 10 | self.y += dy 11 | 12 | def location(self): 13 | print("(" + str(self.x) + ", " + str(self.y) + ")") 14 | 15 | #该类方法将非函数类属性dimension重置为默认值。 16 | @classmethod 17 | def reset(cls): 18 | cls.dimension = 2 19 | 20 | #该静态方法输出一段说明文本,并以给定的符号做装饰。 21 | @staticmethod 22 | def declare(char='*'): 23 | n = 17 24 | line1 = '' 25 | while n > 0: 26 | line1 = line1 + char 27 | n = n - 1 28 | line2 = char+' '+char 29 | print(line1) 30 | print(line2) 31 | print(char+' class Point2D '+char) 32 | print(line2) 33 | print(line1) 34 | -------------------------------------------------------------------------------- /代码/Point2D_new_class.py: -------------------------------------------------------------------------------- 1 | import types 2 | 3 | 4 | #定义将作为Point2D类的__init__属性的函数。 5 | def f1(self, x, y): 6 | self.x = x 7 | self.y = y 8 | 9 | 10 | #定义将作为Point2D类的move属性的函数。 11 | def f2(self, dx, dy): 12 | self.x += dx 13 | self.y += dy 14 | 15 | 16 | #定义将作为Point2D类的location属性的函数。 17 | def f3(self): 18 | print("(" + str(self.x) + ", " + str(self.y) + ")") 19 | 20 | 21 | #定义传入new_class()的exec_body参数的回调函数。 22 | def eb(ns): 23 | ns['dimension'] = 2 24 | ns['__init__'] = f1 25 | ns['move'] = f2 26 | ns['location'] = f3 27 | 28 | 29 | #定义Point2D类。 30 | Point2D = types.new_class('Point2D', exec_body=eb) 31 | 32 | 33 | #修改类所属的模块。 34 | Point2D.__module__ = '__main__' 35 | 36 | #修改函数属性的名字和限定名字。 37 | Point2D.__init__.__name__ = '__init__' 38 | Point2D.__init__.__qualname__ = 'Point2D.__init__' 39 | Point2D.move.__name__ = 'move' 40 | Point2D.move.__qualname__ = 'Point2D.move' 41 | Point2D.location.__name__ = 'location' 42 | Point2D.location.__qualname__ = 'Point2D.location' 43 | 44 | #删除不再需要的标识符。 45 | del f1 46 | del f2 47 | del f3 48 | del eb 49 | 50 | -------------------------------------------------------------------------------- /代码/Point2D_type.py: -------------------------------------------------------------------------------- 1 | #定义将作为Point2D类的__init__方法的函数。 2 | def f1(self, x, y): 3 | self.x = x 4 | self.y = y 5 | 6 | 7 | #定义将作为Point2D类的move方法的函数。 8 | def f2(self, dx, dy): 9 | self.x += dx 10 | self.y += dy 11 | 12 | 13 | #定义将作为Point2D类的location方法的函数。 14 | def f3(self): 15 | print("(" + str(self.x) + ", " + str(self.y) + ")") 16 | 17 | 18 | #定义Point2D类。 19 | Point2D = type('Point2D', (), { 20 | 'dimension': 2, 21 | '__init__': f1, 22 | 'move': f2, 23 | 'location': f3}) 24 | 25 | 26 | #修改函数属性的名字和限定名字。 27 | Point2D.__init__.__name__ = '__init__' 28 | Point2D.__init__.__qualname__ = 'Point2D.__init__' 29 | Point2D.move.__name__ = 'move' 30 | Point2D.move.__qualname__ = 'Point2D.move' 31 | Point2D.location.__name__ = 'location' 32 | Point2D.location.__qualname__ = 'Point2D.location' 33 | 34 | #删除不再需要的标识符。 35 | del f1 36 | del f2 37 | del f3 38 | 39 | -------------------------------------------------------------------------------- /代码/Rune.py: -------------------------------------------------------------------------------- 1 | #定义一个代表北欧符文的类。 2 | class Rune: 3 | #初始化时设置了如下实例属性: 4 | # salutation: 符文的称呼,常量。 5 | # pronunciation: 符文的发音,常量。 6 | # number: 该符文的当前数量,变量。 7 | def __init__(self, s, p, n): 8 | self.salutation = s 9 | self.pronunciation = p 10 | self.number = n 11 | 12 | #重写__setattr__使得只能修改number属性,且无法添加其他实例属性。 13 | def __setattr__(self, name, value): 14 | #只允许设置salutation属性和pronunciation属性一次。 15 | if name == 'salutation' or name == 'pronunciation': 16 | if name in self.__dict__: 17 | return None 18 | #不允许设置未在__init__中添加的属性。 19 | elif name != 'number': 20 | return None 21 | else: 22 | pass 23 | object.__setattr__(self, name, value) 24 | 25 | #重写__delattr__使得无法删除实例属性。 26 | def __delattr__(self, name): 27 | return None 28 | 29 | -------------------------------------------------------------------------------- /代码/abc1.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | 4 | #定义类A。 5 | class A: 6 | #该方法会成为继承A的抽象基类的混入方法。 7 | def a_mixin(self): 8 | print("a_mixin") 9 | 10 | 11 | #定义抽象基类B。 12 | class B(metaclass=abc.ABCMeta): 13 | #该方法是B的抽象方法。 14 | @abc.abstractmethod 15 | def b(self): 16 | print("b") 17 | 18 | 19 | #定义抽象基类C。 20 | class C(abc.ABC): 21 | #该类方法是C的抽象方法。 22 | @classmethod 23 | @abc.abstractmethod 24 | def c(cls): 25 | print("c") 26 | 27 | #该方法是C的混入方法。 28 | def c_mixin(self): 29 | print("c_mixin") 30 | 31 | 32 | #定义抽象基类D。 它继承了类A,因此还具有混入方法a_mixin()。 33 | class D(A, metaclass=abc.ABCMeta): 34 | #该静态方法是D的抽象方法。 35 | @staticmethod 36 | @abc.abstractmethod 37 | def d(): 38 | print("d") 39 | 40 | 41 | #定义抽象基类E。 它继承了抽象基类B,因此还具有抽象方法b()。 它也继承了抽象基类C, 42 | # 因此还具有抽象方法c()和混入方法c_mixin()。 43 | class E(B, C): 44 | #该方法是E的混入方法。 45 | def e_mixin(self): 46 | print("e_mixin") 47 | 48 | 49 | #定义类F,它继承了抽象基类D。 50 | class F(D): 51 | #重写D的抽象方法d()。 52 | @staticmethod 53 | def d(): 54 | print("F's implementation of d()") 55 | #通过super()调用D的d()。 这是通过super()访问基类的静态方法的例子。 56 | super(F, F).d() 57 | 58 | 59 | #定义类G,它继承了抽象基类E。 60 | class G(E): 61 | #重写B的抽象方法b()。 62 | def b(self): 63 | print("G's implementation of b()") 64 | #通过super()调用B的b()。 这是通过super()访问基类的方法的例子。 65 | super().b() 66 | 67 | #重写C的抽象方法c()。 68 | @classmethod 69 | def c(cls): 70 | print("G's implementation of c()") 71 | #通过super()调用C的c()。 这是通过super()访问基类的类方法的例子。 72 | super().c() 73 | 74 | 75 | -------------------------------------------------------------------------------- /代码/abc3.py: -------------------------------------------------------------------------------- 1 | import collections.abc 2 | 3 | 4 | #定义继承Sequence的抽象基类。 5 | class MySequence(collections.abc.Sequence): 6 | #重写__subclasshook__。 7 | @classmethod 8 | def __subclasshook__(cls, subclass): 9 | #仅当通过MySequence调用该属性时才需要做判断,通过MySequence的子类调用该 10 | # 属性时将直接返回NotImplemented。 11 | if cls is MySequence: 12 | #Sequence的虚子类必须是Collection的虚子类。 13 | if not issubclass(subclass, collections.abc.Collection): 14 | return False 15 | #Sequence的虚子类必须是Iterable的虚子类。 16 | if not issubclass(subclass, collections.abc.Iterable): 17 | return False 18 | #Sequence的虚子类还必须实现__reversed__、__getitem__、index()和 19 | # count()。 20 | if hasattr(subclass, "__reversed__") and\ 21 | hasattr(subclass, "__getitem__") and\ 22 | hasattr(subclass, "index") and\ 23 | hasattr(subclass, "count"): 24 | return True 25 | #无法通过上面的条件判断时,继续__subclasscheck__的后续步骤。 26 | return NotImplemented 27 | 28 | 29 | -------------------------------------------------------------------------------- /代码/abc4.py: -------------------------------------------------------------------------------- 1 | import collections.abc 2 | 3 | 4 | #自定义一个类,它基于映射实现不可变序列的基本功能,但没有实现__reversed__、index()和 5 | # count()。 6 | class SeqExample1(collections.abc.Mapping): 7 | #基于一个映射设置序列,键值对转换为序列对象的实例属性,并自动计算和存储长度。 8 | def __init__(self, d): 9 | self.length = 0 10 | for k, v in d.items(): 11 | setattr(self, k, v) 12 | self.length += 1 13 | 14 | #基于实例属性动态生成一个列表,然后返回该列表的迭代器。 15 | def __iter__(self): 16 | l = [] 17 | for key in self.__dict__: 18 | if key[0] != "_" and key != "length": 19 | l.append(getattr(self, key)) 20 | return iter(l) 21 | 22 | #返回储存的序列长度。 23 | def __len__(self): 24 | return self.length 25 | 26 | #将键转化为实例属性。 27 | def __getitem__(self, key): 28 | return getattr(self, key) 29 | 30 | 31 | #自定义一个类,它继承了SeqExample1,额外实现了__reversed__、index()和count()。 32 | class SeqExample2(SeqExample1): 33 | #基于实例属性动态生成一个列表,将其反向,然后返回该列表的迭代器。 34 | def __reversed__(self): 35 | l = [] 36 | for key in self.__dict__: 37 | if key[0] != "_" and key != "length": 38 | l.append(getattr(self, key)) 39 | l.reverse() 40 | return iter(l) 41 | 42 | #遍历实例属性以根据值查找键。 43 | def index(self, value): 44 | for key in self.__dict__: 45 | if key[0] != "_" and key != "length": 46 | if getattr(self, key) == value: 47 | return key 48 | raise ValueError(f"{value} not in sequence") 49 | 50 | #搜索实例属性以计算值的出现次数。 51 | def count(self, value): 52 | n = 0 53 | for key in self.__dict__: 54 | if key[0] != "_" and key != "length": 55 | if getattr(self, key) == value: 56 | n += 1 57 | return n 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /代码/annotation1.py: -------------------------------------------------------------------------------- 1 | #定义一个重复字符串的函数,并通过标注说明: 2 | # 形式参数s需被传入一个字符串。 3 | # 形式参数n需被传入一个整数。 4 | # 返回值是一个字符串。 5 | def str_multiplier(s: str, n: int = 2) -> str: 6 | return s * n 7 | 8 | #调用该函数,并按标注的要求传入实际参数。 9 | print(str_multiplier("abc")) 10 | 11 | #调用该函数,给s传入一个二进制串。 12 | print(str_multiplier(b"01", 3)) 13 | 14 | #调用该函数,给s传入一个整数,给n传入一个浮点数。 15 | print(str_multiplier(10, 4.5)) 16 | -------------------------------------------------------------------------------- /代码/annotation2.py: -------------------------------------------------------------------------------- 1 | import random 2 | import typing 3 | 4 | #该全局变量的标注说明它应该引用一个浮点数。 5 | m: float = 1.0 6 | 7 | 8 | #定义一个函数,该函数本身没有标注,但其内的本地变量具有标注。 9 | def arith_seq(n): 10 | #声明m是全局变量。这里不能有标注。 11 | global m 12 | 13 | #该本地变量的标注说明它应该引用一个整数。 14 | start: int = random.randrange(3) 15 | 16 | #该本地变量的标注说明它应该引用一个整数列表。 17 | seq: list[int] = [] 18 | 19 | #for语句中的变量不能有标注,故只能将标注单独写一行。 i的标注说明它应该引用一个 20 | # 复数,但被赋值整数,不符合其标注。 21 | i: complex 22 | for i in range(n): 23 | #seq被添加浮点数,不符合其标注。 24 | seq.append(start + i*m) 25 | 26 | def result(): 27 | #声明seq是外层本地变量。这里不能有标注。 28 | nonlocal seq 29 | print(seq) 30 | 31 | return result 32 | 33 | 34 | #m的标注被修改,但这在类型检查中会被视为错误,不起作用。 35 | m: complex 36 | #m被赋值一个复数,不符合其标注。 37 | m = 2 + 0j 38 | 39 | 40 | #定义一个类。 41 | class GeoSeq(): 42 | #该类变量的标注说明它应该引用一个浮点数,且被所有GeoSeq类的对象共享。 43 | # 它被赋值一个复数,不符合其标注。 44 | m: typing.ClassVar[float] = m 45 | 46 | #该类变量的标注说明它应该引用一个整数,且被当成同名实例变量的默认值使用。 47 | start: int = 1 48 | 49 | #__init__方法中的本地变量就是实例变量。 50 | def __init__(self, n): 51 | #该实例变量的标注说明它应该引用一个整数。 52 | self.n: int = n 53 | #该实例变量的标注说明它应该引用一个整数。 54 | self.start: int = random.randrange(3) 55 | if self.start == 0: 56 | self.start = GeoSeq.start 57 | 58 | #该方法中的本地变量也有标注。 59 | def __enter__(self): 60 | #该本地变量的标注说明它应该引用一个浮点数列表。 61 | seq: list[float] = [] 62 | #同样,for语句中的变量不能有标注。 i的标注说明它应该引用一个整数。 63 | i: int 64 | for i in range(self.n): 65 | seq.append(self.start * GeoSeq.m**i) 66 | return seq 67 | 68 | def __exit__(self, exc_type, exc_value, traceback): 69 | return False 70 | 71 | 72 | #显示等差数列。 73 | f = arith_seq(5) 74 | f() 75 | 76 | #显示等比数列。 77 | o = GeoSeq(5) 78 | #with语句中的变量不能有标注,故只能将标注单独写一行。 result的标注说明它应该引用一个 79 | # 字符串列表,但实际被赋值一个复数列表,不符合其标注。 80 | result: list[str] 81 | with o as result: 82 | #解包赋值中的变量不能有标注,故只能分别将每个变量的标注单独写一行。 这些变量标注 83 | # 说明它们都应引用一个浮点数,但实际都被赋值一个复数,不符合其标注。 84 | a1: float 85 | a2: float 86 | a3: float 87 | a4: float 88 | a5: float 89 | a1, a2, a3, a4, a5 = result 90 | print(f"[{a1}, {a2}, {a3}, {a4}, {a5}]") 91 | -------------------------------------------------------------------------------- /代码/annotation3.pyi: -------------------------------------------------------------------------------- 1 | import functools 2 | import typing 3 | import random 4 | 5 | @functools.total_ordering 6 | class Pocker: 7 | SPADE: str 8 | HEART: str 9 | CLUB: str 10 | DIAMOND: str 11 | 12 | def __init__(self, suit: typing.Annotated[int, range(1, 5)], rank: typing.Annotated[int, range(1, 14)]): ... 13 | 14 | def __repr__(self):... 15 | 16 | __str__ = __repr__ 17 | 18 | #使用装饰器@typing.no_type_check以跳过静态类型检查。 19 | @typing.no_type_check 20 | def __eq__(self, other: "Pocker"): ... 21 | 22 | def __lt__(self, other: "Pocker"): ... 23 | 24 | 25 | class Draw(Pocker): 26 | def __init__(self, who: str): ... 27 | 28 | def compare(self, other: "Draw") -> int: ... 29 | 30 | 31 | if typing.TYPE_CHECKING: 32 | draw1 = Draw("Jimmy") 33 | draw2 = Draw("Nacy") 34 | draw3 = Draw(None) 35 | draw1.compare(draw2) 36 | print("") 37 | draw2.compare(draw3) 38 | print("") 39 | draw3.compare(draw1) 40 | -------------------------------------------------------------------------------- /代码/argv.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | print(sys.argv) 4 | -------------------------------------------------------------------------------- /代码/arithmetic_calculator.py: -------------------------------------------------------------------------------- 1 | #该函数包含如下参数: 2 | # 仅位置参数op取如下字符串来指定运算: 3 | # 'add': 加法 4 | # 'sub': 减法 5 | # 'mult': 乘法 6 | # 'div': 除法 7 | # 位置或关键字参数x和y为两个操作数,取浮点数。 8 | # 仅关键字参数floordiv取布尔值,以表明是否进行整除。 9 | def arithmetic_calculator(op, /, x, y, *, floordiv): 10 | #确保两个操作数都是浮点数。 11 | x = float(x) 12 | y = float(y) 13 | 14 | #根据指定的运算返回相应结果。 如果指定的运算不能识别,则返回NotImplemented。 15 | if op == 'add': 16 | return x + y 17 | elif op == 'sub': 18 | return x - y 19 | elif op == 'mult': 20 | return x * y 21 | elif op == 'div': 22 | if floordiv: 23 | return x // y 24 | else: 25 | return x / y 26 | else: 27 | return NotImplemented 28 | 29 | -------------------------------------------------------------------------------- /代码/async_comprehension.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import sys 3 | 4 | 5 | #定义用于实现异步推导式的异步迭代器类。 6 | class MyAsyncIterator: 7 | def __init__(self, n): 8 | self.max_n = int(n) 9 | self.n = 0 10 | 11 | def __aiter__(self): 12 | return self 13 | 14 | async def __anext__(self): 15 | await asyncio.sleep(0.3) 16 | if self.n >= self.max_n: 17 | raise StopAsyncIteration() 18 | self.n += 1 19 | return self.n 20 | 21 | 22 | async def main(): 23 | #验证异步列表推导式。 24 | l = [x*y async for x in MyAsyncIterator(3) for y in 'ab' + 'c' if not (x==2 and y=='b')] 25 | print(l) 26 | #验证异步集合推导式。 27 | st = {(x, y) async for x in MyAsyncIterator(9) if x%3 !=0 for y in range(x, 10) if y*x > 50} 28 | print(st) 29 | #验证异步字典推导式。 30 | d = {x-1: (x-1)**2 async for x in MyAsyncIterator(10)} 31 | print(d) 32 | sys.exit(0) 33 | 34 | 35 | if __name__ == "__main__": 36 | asyncio.run(main()) 37 | -------------------------------------------------------------------------------- /代码/async_context_manager.py: -------------------------------------------------------------------------------- 1 | import math 2 | import asyncio 3 | import sys 4 | 5 | 6 | #自定义一个异步上下文管理器类。 7 | class MyAsyncContextManager(): 8 | async def __aenter__(self): 9 | await asyncio.sleep(1) 10 | def f(x, y): 11 | return math.sqrt(x)/y 12 | return f 13 | 14 | async def __aexit__(self, exc_type, exc_value, traceback): 15 | if exc_type == TypeError: 16 | print('Please enter two numbers!') 17 | return True 18 | elif exc_type == ValueError: 19 | print('x must be non-negative!') 20 | return True 21 | else: 22 | return False 23 | 24 | 25 | #该协程函数通过async with语句使用自定义异步上下文管理器。 26 | async def g(x, y): 27 | async with MyAsyncContextManager() as f: 28 | print(f(x, y)) 29 | 30 | 31 | async def main(): 32 | await g(1, 2) 33 | await g('a', 'b') 34 | await g(-1, 2) 35 | await g(1, 0) 36 | sys.exit(0) 37 | 38 | 39 | if __name__ == "__main__": 40 | asyncio.run(main()) 41 | 42 | -------------------------------------------------------------------------------- /代码/async_debug1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | 7 | async def coro(): 8 | pass 9 | 10 | 11 | async def main(): 12 | if len(sys.argv) < 2: 13 | sys.exit(1) 14 | try: 15 | #根据第一个命令行参数设置协程溯源的深度。 16 | d = int(sys.argv[1]) 17 | sys.set_coroutine_origin_tracking_depth(d) 18 | #创建一个任务并执行。 19 | task = asyncio.create_task(coro()) 20 | await task 21 | #取得该任务包装的协程。 22 | cr = task.get_coro() 23 | #取得并显示当前协程溯源的深度。 24 | otd = sys.get_coroutine_origin_tracking_depth() 25 | print(f"origin tracking depth: {otd}") 26 | #显示协程溯源信息。 27 | print(f"cr_origin: {cr.cr_origin}") 28 | sys.exit(0) 29 | except Exception: 30 | sys.exit(1) 31 | 32 | 33 | if __name__ == '__main__': 34 | asyncio.run(main()) 35 | 36 | -------------------------------------------------------------------------------- /代码/async_debug2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | #该全局变量控制着协程是否抛出异常。 7 | #fail = False 8 | fail = True 9 | 10 | 11 | #该协程可能执行完成,也可能抛出异常。 12 | async def coro(): 13 | if fail: 14 | raise RuntimeError() 15 | 16 | 17 | #该函数分析任务包装协程的栈。 18 | def show_stack(task, l): 19 | #获得该任务包装协程的栈框架并显示。 20 | stack = task.get_stack(limit=l) 21 | print(f"{task.get_name()}'s stack frames:") 22 | print(stack) 23 | print("") 24 | #显示该任务包装协程的栈框架相关信息。 25 | print(f"{task.get_name()}'s stack info:") 26 | task.print_stack(limit=l) 27 | print("") 28 | 29 | 30 | async def main(): 31 | #创建任务task1,但未执行。 32 | task1 = asyncio.create_task(coro(), name="task1") 33 | show_stack(task1, 3) 34 | #执行该任务到它正常返回或抛出异常。 35 | try: 36 | await task1 37 | show_stack(task1, 3) 38 | except Exception: 39 | show_stack(task1, 3) 40 | sys.exit(0) 41 | 42 | 43 | if __name__ == '__main__': 44 | asyncio.run(main()) 45 | 46 | -------------------------------------------------------------------------------- /代码/async_iterator.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import sys 3 | 4 | 5 | #自定义一个异步迭代器类。 6 | class MyAsyncIterator: 7 | def __init__(self, n): 8 | self.max_n = int(n) 9 | self.n = 0 10 | 11 | #满足异步迭代器协议对__aiter__的要求。 12 | def __aiter__(self): 13 | return self 14 | 15 | #满足异步迭代器协议对__anext__的要求。 16 | async def __anext__(self): 17 | await asyncio.sleep(0.3) 18 | if self.n >= self.max_n: 19 | raise StopAsyncIteration() 20 | self.n += 1 21 | return self.n 22 | 23 | 24 | async def main(): 25 | #验证第一个异步可迭代对象。 26 | my_aiter1 = MyAsyncIterator(3) 27 | try: 28 | print("my_aiter1:") 29 | for i in range(4): 30 | print(await anext(my_aiter1)) 31 | except StopAsyncIteration as e: 32 | print(repr(e)) 33 | finally: 34 | print("") 35 | #验证第二个异步可迭代对象。 36 | my_aiter2 = MyAsyncIterator(2) 37 | print("my_aiter2:") 38 | for i in range(4): 39 | print(await anext(my_aiter2, -1)) 40 | print("") 41 | #验证第三个异步可迭代对象。 42 | my_aiter3 = MyAsyncIterator(-10) 43 | print("my_aiter3:") 44 | for i in range(4): 45 | print(await anext(my_aiter3, False)) 46 | print("") 47 | #验证async for语句。 48 | print("async for:") 49 | async for n in MyAsyncIterator(5): 50 | print(n) 51 | sys.exit(0) 52 | 53 | 54 | if __name__ == "__main__": 55 | asyncio.run(main()) 56 | 57 | 58 | -------------------------------------------------------------------------------- /代码/boolean_calculator.py: -------------------------------------------------------------------------------- 1 | #该函数包含如下参数: 2 | # 位置或关键字参数x、y和z为三个操作数,可以为任意对象。 对于一元操作,y和z取默认实 3 | # 参值。 对于二元操作,z取默认实参值。 4 | # 仅关键字参数boolean取布尔值,以表明对于二元操作和三元操作,是否将返回的对象转换为 5 | # 布尔值,默认不转换。 6 | # 仅关键字参数op取如下字符串来指定操作类型: 7 | # 'bool': 一元操作逻辑值检测。 8 | # 'not': 一元操作逻辑非。 9 | # 'and': 二元操作逻辑与。 10 | # 'or': 二元操作逻辑或。 11 | # 'switch': 三元操作... if ... else ...。 12 | def boolean_calculator( 13 | x, y=NotImplemented, 14 | z=NotImplemented, *, 15 | boolean=False, op 16 | ): 17 | 18 | #处理一元逻辑操作。 19 | if op in ('bool', 'not'): 20 | #验证操作数是否为NotImplemented。 21 | if x is NotImplemented: 22 | return NotImplemented 23 | else: 24 | #逻辑值检测。 25 | if op == 'bool': 26 | return bool(x) 27 | #逻辑非。 28 | else: 29 | return not x 30 | 31 | #处理二元逻辑操作。 32 | elif op in ('and', 'or'): 33 | #验证操作数是否为NotImplemented。 34 | if x is NotImplemented or y is NotImplemented: 35 | return NotImplemented 36 | else: 37 | #逻辑与。如果boolean取True则返回布尔值。 38 | if op == 'and': 39 | return bool(x and y) if boolean else (x and y) 40 | #逻辑或。如果boolean取True则返回布尔值。 41 | else: 42 | return bool(x or y) if boolean else (x or y) 43 | 44 | #处理三元逻辑操作。 45 | elif op == 'switch': 46 | #验证操作数是否为NotImplemented。 47 | if (x is NotImplemented 48 | or y is NotImplemented 49 | or z is NotImplemented): 50 | return NotImplemented 51 | else: 52 | #... if ... else ... 53 | obj = x if y else z 54 | #如果boolean取True则返回布尔值。 55 | if boolean: 56 | return bool(obj) 57 | else: 58 | return obj 59 | 60 | #对于不能识别的操作,返回NotImplemented。 61 | else: 62 | return NotImplemented 63 | 64 | -------------------------------------------------------------------------------- /代码/bubble_sort.py: -------------------------------------------------------------------------------- 1 | #该函数以冒泡排序算法对列表进行排序,其参数compare需被传入一个返回布尔值的函数, 2 | # 而该函数自身的返回值是排好序的列表。 3 | def bubble_sort(lt, compare=lambda a, b: a < b): 4 | #如果传入列表的成员数少于2,直接返回该列表。 5 | lt_len = len(lt) 6 | if lt_len < 2: 7 | return lt 8 | 9 | #创建一个新列表,然后依次取出原列表的成员,与新列表的已有成员基于回调函数进行 10 | # 比较,在回调函数第一次返回True的索引处插入该成员。 11 | nlt = [lt[0]] 12 | i = 1 13 | while i < lt_len: 14 | nlt_len = len(nlt) 15 | j = 0 16 | while j < nlt_len: 17 | if compare(lt[i], nlt[j]): 18 | nlt.insert(j, lt[i]) 19 | break 20 | j = j + 1 21 | else: 22 | nlt.append(lt[i]) 23 | i = i + 1 24 | 25 | return nlt 26 | 27 | -------------------------------------------------------------------------------- /代码/cache.py: -------------------------------------------------------------------------------- 1 | import time 2 | import functools 3 | 4 | 5 | #定义一个无缓存功能的斐波拉契序列生成函数。 6 | def fibonacci(n): 7 | if n < 2: 8 | return 1 9 | else: 10 | return fibonacci(n-1) + fibonacci(n-2) 11 | 12 | 13 | #定义一个有缓存功能的斐波拉契序列生成函数。 14 | @functools.cache 15 | def fibonacci_cache(n): 16 | if n < 2: 17 | return 1 18 | else: 19 | return fibonacci_cache(n-1) + fibonacci_cache(n-2) 20 | 21 | 22 | #定义一个统计函数执行时间的函数。 23 | def process_time(func, *args, **kwargs): 24 | starttime = time.time() 25 | func(*args, **kwargs) 26 | endtime = time.time() 27 | return endtime - starttime 28 | 29 | -------------------------------------------------------------------------------- /代码/calculator_factory.py: -------------------------------------------------------------------------------- 1 | #该函数包含如下参数: 2 | # 位置或关键字参数op取如下字符串来指定操作类型: 3 | # 'add': 加法。 4 | # 'sub': 减法。 5 | # 'mult': 乘法。 6 | # 'div': 除法。 7 | # 'bool': 逻辑值检测。 8 | # 'not': 逻辑非。 9 | # 'and': 逻辑与。 10 | # 'or': 逻辑或。 11 | # 'switch': ... if ... else ...。 12 | # 仅关键字参数modifiers接收所有修饰符。可能的修饰符包括: 13 | # floordiv: 取布尔值,以表明是否进行整除,默认不进行。 14 | # boolean: 取布尔值,以表明对于二元和三元逻辑运算,是否将返回的对象转换为布尔值, 15 | # 默认不转换。 16 | def calculator_factory(op, **modifiers): 17 | if op == 'add': 18 | return lambda x, y: float(x) + float(y) 19 | elif op == 'sub': 20 | return lambda x, y: float(x) - float(y) 21 | elif op == 'mult': 22 | return lambda x, y: float(x) * float(y) 23 | elif op == 'div': 24 | if 'floordiv' in modifiers and modifiers['floordiv']: 25 | return lambda x, y: float(x) // float(y) 26 | else: 27 | return lambda x, y: float(x) / float(y) 28 | elif op == 'bool': 29 | return lambda x: bool(x) 30 | elif op == 'not': 31 | return lambda x: not x 32 | elif op == 'and': 33 | if 'boolean' in modifiers and modifiers['boolean']: 34 | return lambda x, y: bool(x and y) 35 | else: 36 | return lambda x, y: x and y 37 | elif op == 'or': 38 | if 'boolean' in modifiers and modifiers['boolean']: 39 | return lambda x, y: bool(x or y) 40 | else: 41 | return lambda x, y: x or y 42 | elif op == 'switch': 43 | if 'boolean' in modifiers and modifiers['boolean']: 44 | return lambda x, y, z: bool(x if y else z) 45 | else: 46 | return lambda x, y, z: x if y else z 47 | else: 48 | return NotImplemented 49 | 50 | -------------------------------------------------------------------------------- /代码/class_decorator1.py: -------------------------------------------------------------------------------- 1 | #定义被用作装饰器的函数。 2 | def classname(cls): 3 | if not hasattr(cls, 'classname'): 4 | def classname(self): 5 | return type(self).__name__ 6 | classname.__qualname__ = cls.__qualname__ + '.classname' 7 | classname.__module__ = cls.__module__ 8 | cls.classname = classname 9 | return cls 10 | 11 | 12 | #定义被装饰的目标类A。 13 | @classname 14 | class A: 15 | pass 16 | 17 | 18 | #定义被装饰的目标B。 19 | @classname 20 | class B: 21 | pass 22 | 23 | 24 | #定义被装饰的目标C。 25 | @classname 26 | class C: 27 | def classname(self): 28 | return 'Class Name: C' 29 | 30 | 31 | -------------------------------------------------------------------------------- /代码/class_decorator2.py: -------------------------------------------------------------------------------- 1 | #定义被用作装饰器的类。 2 | class classname: 3 | def __init__(self, cls): 4 | if not hasattr(cls, 'classname'): 5 | def classname(self): 6 | return type(self).__name__ 7 | classname.__qualname__ = cls.__qualname__ + '.classname' 8 | classname.__module__ = cls.__module__ 9 | cls.classname = classname 10 | self.cls = cls 11 | self.__name__ = cls.__name__ 12 | self.__qualname__ = cls.__qualname__ 13 | self.__module__ = cls.__module__ 14 | self.__doc__ = cls.__doc__ 15 | self.__annotations__ = cls.__annotations__ 16 | self.__bases__ = cls.__bases__ 17 | self.__mro__ = cls.__mro__ 18 | 19 | def __call__(self, *args, **kwargs): 20 | return self.cls(*args, **kwargs) 21 | 22 | 23 | #定义被装饰的目标类A。 24 | @classname 25 | class A: 26 | pass 27 | 28 | 29 | #定义被装饰的目标B。 30 | @classname 31 | class B: 32 | pass 33 | 34 | 35 | #定义被装饰的目标C。 36 | @classname 37 | class C: 38 | def classname(self): 39 | return 'Class Name: C' 40 | 41 | 42 | -------------------------------------------------------------------------------- /代码/clock_descriptor.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timezone, timedelta 2 | 3 | 4 | #定义Clock类,其实例代表处于某时区的本地时钟。 由于该类实现了__get__,所以该类的实例 5 | # 都是描述器。 6 | class Clock: 7 | #实例属性tz储存着该时钟所在时区。 8 | def __init__(self, h): 9 | h = int(h) 10 | delta = timedelta(hours=h) 11 | self.tz = timezone(delta) 12 | 13 | #读取该时钟时返回“hh:mm:ss”格式的本地时间。 14 | def __get__(self, instance, owner=None): 15 | t = datetime.now(self.tz) 16 | return str(t.hour) + ':' + str(t.minute) + ':' + str(t.second) 17 | 18 | 19 | #定义WorldClock类,其每个类属性以一个城市命名,引用一个处于该城市所在时区的时钟描述器。 20 | class WorldClock: 21 | honolulu = Clock(-11) #西11区,火奴鲁鲁。 22 | hawaii = Clock(-10) #西10区,夏威夷。 23 | juneau = Clock(-9) #西9区,朱诺。 24 | los_angeles = Clock(-8) #西8区,洛杉矶。 25 | mexico_city = Clock(-7) #西7区,墨西哥城。 26 | chicago = Clock(-6) #西6区,芝加哥。 27 | washington = Clock(-5) #西5区,华盛顿。 28 | buenos_aires = Clock(-4) #西4区,布宜诺斯艾利斯。 29 | brasilia = Clock(-3) #西3区,巴西利亚。 30 | greenland = Clock(-2) #西2区,格陵兰岛。 31 | conakry = Clock(-1) #西1区,科纳克里。 32 | london = Clock(0) #UTC时间,伦敦。 33 | berlin = Clock(1) #东1区,柏林。 34 | cairo = Clock(2) #东2区,开罗。 35 | moscow = Clock(3) #东3区,莫斯科。 36 | abu_dhabi = Clock(4) #东4区,阿布扎比。 37 | new_delhi = Clock(5) #东5区,新德里。 38 | almaty = Clock(6) #东6区,阿拉木图。 39 | singapore = Clock(7) #东7区,新加坡。 40 | beijing = Clock(8) #东8区,北京。 41 | tokyo = Clock(9) #东9区,东京。 42 | melbourne = Clock(10) #东10区,墨尔本。 43 | honiara = Clock(11) #东11区,霍尼亚拉。 44 | wellington = Clock(12) #东12区,惠灵顿。 45 | 46 | -------------------------------------------------------------------------------- /代码/closure1.py: -------------------------------------------------------------------------------- 1 | #定义外层函数f1。 2 | def f1(a, b): 3 | x = a 4 | y = b 5 | #定义内层函数f2。 6 | def f2(z): 7 | return (x, y, z) 8 | #该return语句使f2成为了f1的闭包。 9 | return f2 10 | 11 | -------------------------------------------------------------------------------- /代码/closure2.py: -------------------------------------------------------------------------------- 1 | def outer(): 2 | #定义一个用于储存闭包的列表。 3 | inner = list() 4 | n = 3 5 | while n > 0: 6 | #循环三次,每次都产生一个返回自由变量n的闭包。 7 | def f(): 8 | return n 9 | inner.append(f) 10 | n = n-1 11 | return inner 12 | 13 | -------------------------------------------------------------------------------- /代码/context_manager.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | class MyContextManager(): 5 | def __enter__(self): 6 | def f(x, y): 7 | return math.sqrt(x)/y 8 | return f 9 | 10 | def __exit__(self, exc_type, exc_value, traceback): 11 | if exc_type == TypeError: 12 | print('Please enter two numbers!') 13 | return True 14 | elif exc_type == ValueError: 15 | print('x must be non-negative!') 16 | return True 17 | else: 18 | return False 19 | 20 | -------------------------------------------------------------------------------- /代码/coroutine1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | 7 | #该协程函数创建的协程代表秒表。 sec参数传入需计时的秒数。 8 | async def stopwatch(sec): 9 | n = 0 10 | while n < sec: 11 | #输出当前剩余秒数并立即显示。 12 | sys.stdout.write(str(sec - n) + ' ') 13 | sys.stdout.flush() 14 | #等待一个耗时1秒的协程执行完成。 15 | n = await asyncio.sleep(1, n + 1) 16 | #输出剩余秒数0并立即显示。 17 | sys.stdout.write('0\n') 18 | sys.stdout.flush() 19 | 20 | 21 | #该主协程函数将第一个命令行参数解读为需计时的秒数。 22 | async def main(): 23 | if len(sys.argv) < 2: 24 | sys.exit(1) 25 | try: 26 | sec = int(sys.argv[1]) 27 | #等待stopwatch()返回的协程执行完成。 28 | await stopwatch(sec) 29 | sys.exit(0) 30 | except Exception: 31 | sys.exit(1) 32 | 33 | 34 | #执行主协程函数创建的主协程。 35 | if __name__ == '__main__': 36 | asyncio.run(main()) 37 | -------------------------------------------------------------------------------- /代码/coroutine10.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | task1 = None 7 | task2 = None 8 | 9 | 10 | async def n(bound): 11 | for i in range(bound): 12 | print('n:', i) 13 | await asyncio.sleep(1) 14 | 15 | 16 | async def n_square(bound): 17 | for i in range(bound): 18 | print('n square:', i * i) 19 | await asyncio.sleep(1) 20 | 21 | 22 | async def print_square_table(bound): 23 | global task1, task2 24 | task1 = asyncio.create_task(n(bound)) 25 | task2 = asyncio.create_task(n_square(bound)) 26 | #将task1和task2聚集成一个任务。 27 | await asyncio.gather(task1, task2) 28 | 29 | 30 | async def cancel_print(task): 31 | await asyncio.sleep(2.9) 32 | task.cancel() 33 | 34 | 35 | async def main(): 36 | global task1, task2 37 | if len(sys.argv) < 2: 38 | sys.exit(1) 39 | try: 40 | bound = int(sys.argv[1]) 41 | task = asyncio.create_task(print_square_table(bound)) 42 | cancel_task = asyncio.create_task(cancel_print(task)) 43 | await task 44 | await cancel_task 45 | except asyncio.CancelledError: 46 | pass 47 | print("task.cancelled():", task.cancelled()) 48 | print("task.done():", task.done()) 49 | print("task1.cancelled():", task1.cancelled()) 50 | print("task1.done():", task1.done()) 51 | print("task2.cancelled():", task2.cancelled()) 52 | print("task2.done():", task2.done()) 53 | while not task1.done() or not task2.done(): 54 | await asyncio.sleep(1) 55 | sys.exit(0) 56 | 57 | 58 | if __name__ == '__main__': 59 | asyncio.run(main()) 60 | -------------------------------------------------------------------------------- /代码/coroutine11.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | 7 | #foo()创建的协程会以1秒为间隔打印0~4。 8 | async def foo(): 9 | for i in range(5): 10 | print("foo:", i) 11 | await asyncio.sleep(1) 12 | return i 13 | 14 | 15 | #bar()创建的协程会以1秒为间隔打印0~2,然后被取消。 16 | async def bar(): 17 | for i in range(5): 18 | print("bar:", i) 19 | if i > 1: 20 | asyncio.current_task().cancel() 21 | await asyncio.sleep(1) 22 | 23 | 24 | #baz()创建的协程会以1秒为间隔打印0~3,然后抛出RuntimeError异常。 25 | async def baz(): 26 | for i in range(5): 27 | print("baz:", i) 28 | if i > 2: 29 | raise RuntimeError() 30 | await asyncio.sleep(1) 31 | 32 | 33 | async def main(): 34 | result = None 35 | try: 36 | #聚集foo()、bar()和baz()。 37 | task = asyncio.gather(foo(), bar(), baz()) 38 | #task = asyncio.gather(foo(), bar(), baz(), return_exceptions=True) 39 | await task 40 | except RuntimeError as e: 41 | print("RuntimeError") 42 | except asyncio.CancelledError as e: 43 | print("CancelledError") 44 | #等待3秒钟,以确保所有被聚集的任务执行完。 45 | await asyncio.sleep(3) 46 | #检查task的状态。 47 | print("task.cancelled() ==", task.cancelled()) 48 | print("task.done() ==", task.done()) 49 | try: 50 | print("task.result() ==", task.result()) 51 | except BaseException as e: 52 | print("task.result() ==", repr(e)) 53 | sys.exit(0) 54 | 55 | 56 | if __name__ == '__main__': 57 | asyncio.run(main()) 58 | -------------------------------------------------------------------------------- /代码/coroutine12.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | 7 | async def foo(): 8 | for i in range(5): 9 | print("foo:", i) 10 | await asyncio.sleep(1) 11 | return i 12 | 13 | 14 | async def bar(): 15 | for i in range(5): 16 | print("bar:", i) 17 | if i > 1: 18 | asyncio.current_task().cancel() 19 | await asyncio.sleep(1) 20 | 21 | 22 | async def baz(): 23 | for i in range(5): 24 | print("baz:", i) 25 | if i > 2: 26 | raise RuntimeError() 27 | await asyncio.sleep(1) 28 | 29 | 30 | async def main(): 31 | #创建任务时设置了任务名字。 32 | task1 = asyncio.create_task(foo(), name="foo") 33 | task2 = asyncio.create_task(bar(), name="bar") 34 | task3 = asyncio.create_task(baz(), name="baz") 35 | #将三个任务合并成一个协程来运行。 36 | coro = asyncio.wait([task1, task2, task3]) 37 | #coro = asyncio.wait([task1, task2, task3], return_when=asyncio.FIRST_COMPLETED) 38 | #coro = asyncio.wait([task1, task2, task3], return_when=asyncio.FIRST_EXCEPTION) 39 | #coro = asyncio.wait([task1, task2, task3], timeout=1.5) 40 | done, pending = await coro 41 | #查看已完成或已取消任务。 42 | print(f"\n{len(done)} tasks done:") 43 | for task in done: 44 | print(f"{task.get_name()}.cancelled() == {task.cancelled()}") 45 | print(f"{task.get_name()}.done() == {task.done()}") 46 | try: 47 | print(f"{task.get_name()}.result() == {task.result()}\n") 48 | except BaseException as e: 49 | print(f"{task.get_name()}.result() == {repr(e)}\n") 50 | #查看未完成任务。 51 | print(f"\n{len(pending)} tasks pending:") 52 | for task in pending: 53 | print(f"{task.get_name()}.cancelled() == {task.cancelled()}") 54 | print(f"{task.get_name()}.done() == {task.done()}") 55 | try: 56 | print(f"{task.get_name()}.result() == {task.result()}\n") 57 | except BaseException as e: 58 | print(f"{task.get_name()}.result() == {repr(e)}\n") 59 | sys.exit(0) 60 | 61 | 62 | if __name__ == '__main__': 63 | asyncio.run(main()) 64 | -------------------------------------------------------------------------------- /代码/coroutine13.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | 7 | async def foo(): 8 | for i in range(5): 9 | print("foo:", i) 10 | await asyncio.sleep(1) 11 | return i 12 | 13 | 14 | async def bar(): 15 | for i in range(3): 16 | print("bar:", i) 17 | #if i > 0: 18 | # asyncio.current_task().cancel() 19 | await asyncio.sleep(1) 20 | return i 21 | 22 | 23 | async def baz(): 24 | for i in range(4): 25 | print("baz:", i) 26 | #if i > 2: 27 | # raise RuntimeError() 28 | await asyncio.sleep(1) 29 | return i 30 | 31 | 32 | async def main(): 33 | task1 = asyncio.create_task(foo(), name="foo") 34 | task2 = asyncio.create_task(bar(), name="bar") 35 | task3 = asyncio.create_task(baz(), name="baz") 36 | try: 37 | #并行运行三个任务。 38 | for coro in asyncio.as_completed([task1, task2, task3]): 39 | #for coro in asyncio.as_completed([task1, task2, task3], timeout=1.5): 40 | #取得任务执行结果并显示。 41 | result = await coro 42 | print(result) 43 | except (asyncio.CancelledError, asyncio.TimeoutError, RuntimeError) as e: 44 | #如果抛出异常,则显示。 45 | print(repr(e)) 46 | finally: 47 | #取得迭代停止时三个任务的信息,然后取消未完成的任务。 48 | for i in range(1, 4): 49 | codes = f""" 50 | print(f'\\n{{task{i}.get_name()}}.cancelled() == {{task{i}.cancelled()}}') 51 | print(f'{{task{i}.get_name()}}.done() == {{task{i}.done()}}') 52 | try: 53 | print(f'{{task{i}.get_name()}}.result() == {{task{i}.result()}}') 54 | except BaseException as e: 55 | print(f'{{task{i}.get_name()}}.result() == {{repr(e)}}') 56 | if not task{i}.cancelled(): 57 | task{i}.cancel()""" 58 | exec(codes) 59 | sys.exit(0) 60 | 61 | 62 | if __name__ == '__main__': 63 | asyncio.run(main()) 64 | -------------------------------------------------------------------------------- /代码/coroutine14.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | #用一个全局变量来引用动态增添的任务。 7 | task3 = None 8 | 9 | 10 | #该协程函数的参数tg需被传入一个TaskGroup对象。 11 | async def foo(tg): 12 | global task3 13 | for i in range(5): 14 | #取得当前所有未完成的任务。 15 | unfinished_tasks = asyncio.all_tasks() 16 | #显示所有未完成任务的名字。 17 | s = "unfinished tasks: " 18 | for t in unfinished_tasks: 19 | s += t.get_name() + " " 20 | print(s) 21 | #1秒后动态给任务组增添任务baz。 22 | if i == 1: 23 | task3 = tg.create_task(baz(), name="baz") 24 | print("foo:", i) 25 | await asyncio.sleep(1) 26 | return i 27 | 28 | 29 | async def bar(): 30 | for i in range(3): 31 | print("bar:", i) 32 | #2秒后取消任务bar。 33 | if i == 2: 34 | asyncio.current_task().cancel() 35 | await asyncio.sleep(1) 36 | return i 37 | 38 | 39 | async def baz(): 40 | for i in range(4): 41 | print("baz:", i) 42 | #if i == 2: 43 | #raise RuntimeError() 44 | #raise KeyboardInterrupt() 45 | await asyncio.sleep(1) 46 | return i 47 | 48 | 49 | async def main(): 50 | try: 51 | #创建一个任务组,使其包含任务foo和bar。 52 | async with asyncio.TaskGroup() as tg: 53 | task1 = tg.create_task(foo(tg), name="foo") 54 | task2 = tg.create_task(bar(), name="bar") 55 | except (KeyboardInterrupt, BaseExceptionGroup, ExceptionGroup) as e: 56 | #截获TaskGroup对象抛出的异常并显示。 57 | print(repr(e)) 58 | finally: 59 | #显示任务组完成时各任务的状态。 60 | for i in range(1, 4): 61 | codes = f""" 62 | print(f'\\n{{task{i}.get_name()}}.cancelled() == {{task{i}.cancelled()}}') 63 | print(f'{{task{i}.get_name()}}.done() == {{task{i}.done()}}') 64 | try: 65 | print(f'{{task{i}.get_name()}}.result() == {{task{i}.result()}}') 66 | except BaseException as e: 67 | print(f'{{task{i}.get_name()}}.result() == {{repr(e)}}') 68 | if not task{i}.cancelled(): 69 | task{i}.cancel()""" 70 | exec(codes) 71 | sys.exit(0) 72 | 73 | 74 | if __name__ == '__main__': 75 | asyncio.run(main()) 76 | -------------------------------------------------------------------------------- /代码/coroutine15.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import time 6 | import sys 7 | 8 | 9 | #该协程函数创建的协程代表徒步旅行者。 10 | async def hiker(name, barrier): 11 | try: 12 | #该徒步旅行者随机花费0.5~7.0秒走到屏障前。 13 | t = random.uniform(0.5, 7.0) 14 | await asyncio.sleep(t) 15 | #显示该徒步旅行者走到屏障前的时间,以及屏障的状态。 16 | print(f"{name}: I meet the barrier at {time.strftime('%X')}.") 17 | print(f"{name}: n_waiting == {barrier.n_waiting}, broken == {barrier.broken}") 18 | #等待所有徒步旅行者到齐。 如果屏障已经损坏,则立刻抛出 19 | # asyncio.BrokenBarrierError异常。 20 | await barrier.wait() 21 | #显示该徒步旅行者翻越屏障的时间,以及屏障的状态。 22 | print(f"{name}: I cross the barrier at {time.strftime('%X')}.") 23 | print(f"{name}: n_waiting == {barrier.n_waiting}, broken == {barrier.broken}") 24 | except asyncio.BrokenBarrierError: 25 | #显示该旅行者意识到屏障已经损坏的时间,以及屏障的状态。 26 | print(f"{name}: The barrier collapses before {time.strftime('%X')}. Hooray!") 27 | print(f"{name}: n_waiting == {barrier.n_waiting}, broken == {barrier.broken}") 28 | 29 | 30 | #该协程函数创建的协程代表锤子。 它会在5秒钟后破坏屏障。 31 | async def hammer(barrier): 32 | await asyncio.sleep(5) 33 | await barrier.abort() 34 | #await barrier.reset() 35 | 36 | 37 | async def main(): 38 | #创建一个屏障。 39 | barrier = asyncio.Barrier(3) 40 | #创建四个任务并将它们聚集成一个任务。 只有hiker1、hiker2和hiker3需要翻越屏障。 41 | # hammer0将破坏屏障。 42 | hiker1 = asyncio.create_task(hiker("hiker1", barrier)) 43 | hiker2 = asyncio.create_task(hiker("hiker2", barrier)) 44 | hiker3 = asyncio.create_task(hiker("hiker3", barrier)) 45 | hammer0 = asyncio.create_task(hammer(barrier)) 46 | #显示这次徒步旅行开始的时间,然后开始旅行。 47 | print(f"Start at {time.strftime('%X')}") 48 | await asyncio.gather(hiker1, hiker2, hiker3, hammer0) 49 | sys.exit(0) 50 | 51 | 52 | if __name__ == '__main__': 53 | asyncio.run(main()) 54 | -------------------------------------------------------------------------------- /代码/coroutine16.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | 8 | #该协程函数创建的协程当even_event事件被设置时在0.4秒后显示“*”。 9 | async def star(event): 10 | while True: 11 | #等待事件被设置。 12 | await event.wait() 13 | #这里等待0.4秒是人为添加的,其实不需要。 14 | await asyncio.sleep(0.4) 15 | #取消事件的设置。 16 | event.clear() 17 | #处理该事件的代码。 18 | sys.stdout.write("* ") 19 | sys.stdout.flush() 20 | 21 | 22 | #该协程函数创建的协程当odd_event事件被设置时在0.4秒后显示“$”。 23 | async def dollar(event): 24 | while True: 25 | #等待事件被设置。 26 | await event.wait() 27 | #这里等待0.4秒是人为添加的,其实不需要。 28 | await asyncio.sleep(0.4) 29 | #取消事件的设置。 30 | event.clear() 31 | #处理该事件的代码。 32 | sys.stdout.write("$ ") 33 | sys.stdout.flush() 34 | 35 | 36 | #该协程函数创建的协程每隔0.5秒随机生成一个0~100内的整数。 如果该整数是偶数,则设置 37 | # even_event事件;如果该整数是奇数,则设置odd_event事件。 38 | async def num_gen(event1, event2): 39 | while True: 40 | n = random.randrange(100) 41 | if n % 2 == 0: 42 | #设置even_event事件。 43 | event1.set() 44 | else: 45 | #设置odd_event事件。 46 | event2.set() 47 | await asyncio.sleep(0.5) 48 | 49 | 50 | async def main(): 51 | #创建even_event事件,代表num_gen()生成了一个偶数。 52 | even_event = asyncio.Event() 53 | #创建odd_event事件,代表num_gen()生成了一个奇数。 54 | odd_event = asyncio.Event() 55 | #创建三个任务并将它们聚集成一个任务。 56 | task_star = asyncio.create_task(star(even_event)) 57 | task_dollar = asyncio.create_task(dollar(odd_event)) 58 | task_num_gen = asyncio.create_task(num_gen(even_event, odd_event)) 59 | task = asyncio.gather(task_star, task_dollar, task_num_gen) 60 | try: 61 | #运行任务2.6秒。 62 | await asyncio.wait_for(task, 2.6) 63 | except asyncio.TimeoutError: 64 | print("") 65 | #判断任务运行完成时是否还有未处理的事件。 66 | if even_event.is_set(): 67 | #even_event事件未处理。 68 | print("The cancelled symbol is *.") 69 | elif odd_event.is_set(): 70 | #odd_event事件未处理。 71 | print("The cancelled symbol is $.") 72 | else: 73 | #所有事件都已经处理。 74 | print("No symbol is cancelled.") 75 | sys.exit(0) 76 | 77 | 78 | if __name__ == '__main__': 79 | asyncio.run(main()) 80 | -------------------------------------------------------------------------------- /代码/coroutine17.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | 7 | #该协程函数创建的协程以0.1秒为间隔连续显示三个“*”。 8 | async def stars(lock): 9 | try: 10 | while True: 11 | #申请获得锁,进入临界区。 12 | await lock.acquire() 13 | #显示锁的当前状态。 14 | print(f"\nstars: locked == {lock.locked()}") 15 | #显示“*”。 16 | for i in range(3): 17 | await asyncio.sleep(0.1) 18 | sys.stdout.write("*") 19 | sys.stdout.flush() 20 | #释放锁,离开临界区。 21 | lock.release() 22 | except asyncio.CancelledError: 23 | lock.release() 24 | raise 25 | 26 | 27 | #该协程函数创建的协程以0.1秒为间隔连续显示三个“$”。 28 | async def dollars(lock): 29 | try: 30 | while True: 31 | #申请获得锁,进入临界区。 32 | await lock.acquire() 33 | #显示锁的当前状态。 34 | print(f"\ndollars: locked == {lock.locked()}") 35 | #显示“$”。 36 | for i in range(3): 37 | await asyncio.sleep(0.1) 38 | sys.stdout.write("$") 39 | sys.stdout.flush() 40 | #释放锁,离开临界区。 41 | lock.release() 42 | except asyncio.CancelledError: 43 | lock.release() 44 | raise 45 | 46 | 47 | async def main(): 48 | #创建一个关联到标准输出的锁。 49 | lock = asyncio.Lock() 50 | #创建两个任务并将它们聚集成一个任务。 51 | task_stars = asyncio.create_task(stars(lock)) 52 | task_dollars = asyncio.create_task(dollars(lock)) 53 | task = asyncio.gather(task_stars, task_dollars) 54 | try: 55 | #显示锁的当前状态。 56 | print(f"\nlocked == {lock.locked()}") 57 | #运行任务1.1秒。 58 | await asyncio.wait_for(task, 1.1) 59 | except asyncio.TimeoutError: 60 | #显示锁的当前状态。 61 | print(f"\n\nlocked == {lock.locked()}") 62 | sys.exit(0) 63 | 64 | 65 | if __name__ == '__main__': 66 | asyncio.run(main()) 67 | -------------------------------------------------------------------------------- /代码/coroutine18.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | 8 | #该协程函数创建的协程以0.1秒为间隔连续显示三个“*”。 但它等待的是监视器而非锁。 9 | async def stars(cond): 10 | try: 11 | #申请获得底层锁,进入临界区。 12 | await cond.acquire() 13 | while True: 14 | #等待监视器,并释放底层锁,离开临界区。 15 | await cond.wait() 16 | #在这里会重新申请获得底层锁,进入临界区。 17 | for i in range(3): 18 | await asyncio.sleep(0.1) 19 | sys.stdout.write("*") 20 | sys.stdout.flush() 21 | print("") 22 | except asyncio.CancelledError: 23 | #在任务被取消时释放底层锁。 24 | cond.release() 25 | raise 26 | 27 | 28 | #该协程函数创建的协程以0.1秒为间隔连续显示三个“$”。 但它等待的是监视器而非锁。 29 | async def dollars(cond): 30 | try: 31 | #申请获得底层锁,进入临界区。 32 | await cond.acquire() 33 | while True: 34 | #等待监视器,并释放底层锁,离开临界区。 35 | await cond.wait() 36 | #在这里会重新申请获得底层锁,进入临界区。 37 | for i in range(3): 38 | await asyncio.sleep(0.1) 39 | sys.stdout.write("$") 40 | sys.stdout.flush() 41 | print("") 42 | except asyncio.CancelledError: 43 | #在任务被取消时释放底层锁。 44 | cond.release() 45 | raise 46 | 47 | 48 | #该协程函数创建的协程直接通过lock获得和释放底层锁,只要获得了底层锁就会随机生成一个 49 | # 0~100内的整数。 如果该整数是偶数,则通知等待cond1的任务执行。 如果该整数是奇数, 50 | # 则通知等待cond2的任务执行。 51 | async def num_gen(lock, cond1, cond2): 52 | while True: 53 | #申请获得底层锁,进入临界区。 54 | await lock.acquire() 55 | n = random.randrange(100) 56 | if n % 2 == 0: 57 | #通知等待cond1的任务。 58 | cond1.notify() 59 | else: 60 | #通知等待cond2的任务。 61 | cond2.notify() 62 | #释放底层锁,离开临界区。 63 | lock.release() 64 | await asyncio.sleep(0) 65 | 66 | 67 | async def main(): 68 | #创建一个关联到标准输出的锁。 69 | lock = asyncio.Lock() 70 | #创建一个以lock为底层锁,代表生成了偶数的监视器。 71 | cond1 = asyncio.Condition(lock) 72 | #创建一个以lock为底层锁,代表生成了奇数的监视器。 73 | cond2 = asyncio.Condition(lock) 74 | #创建三个任务并将它们聚集成一个任务。 75 | task_num_gen = asyncio.create_task(num_gen(lock, cond1, cond2)) 76 | task_stars = asyncio.create_task(stars(cond1)) 77 | task_dollars = asyncio.create_task(dollars(cond2)) 78 | task = asyncio.gather(task_num_gen, task_stars, task_dollars) 79 | try: 80 | #运行任务2秒。 81 | await asyncio.wait_for(task, 2) 82 | except asyncio.TimeoutError: 83 | pass 84 | sys.exit(0) 85 | 86 | 87 | if __name__ == '__main__': 88 | asyncio.run(main()) 89 | -------------------------------------------------------------------------------- /代码/coroutine2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | 7 | #该协程函数使用了递归。 8 | async def stopwatch(sec): 9 | await asyncio.sleep(1) 10 | if sec <= 0: 11 | sys.stdout.write('0\n') 12 | sys.stdout.flush() 13 | return 14 | else: 15 | sys.stdout.write(str(sec) + ' ') 16 | sys.stdout.flush() 17 | await(stopwatch(sec -1)) 18 | 19 | 20 | async def main(): 21 | if len(sys.argv) < 2: 22 | sys.exit(1) 23 | try: 24 | sec = int(sys.argv[1]) 25 | await stopwatch(sec) 26 | sys.exit(0) 27 | except Exception: 28 | sys.exit(1) 29 | 30 | 31 | if __name__ == '__main__': 32 | asyncio.run(main()) 33 | -------------------------------------------------------------------------------- /代码/coroutine20.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | 8 | #该协程函数创建的协程是生产者。 它们随机睡眠0~1秒的时间,然后随机生成一个0~100内的 9 | # 整数n,最后将元组(name, n)插入无长度限制的LIFO队列stack。 10 | async def producer(stack, sem, name): 11 | while True: 12 | t = random.random() 13 | await asyncio.sleep(t) 14 | n = random.randrange(100) 15 | #生成数据项。 16 | stack.append((name, n)) 17 | print(f"append ({name}, {n})") 18 | print(f" stack size: {len(stack)}") 19 | #释放信号量,唤醒被挂起的消费者,否则使计数器加1。 20 | sem.release() 21 | 22 | 23 | #该协程函数创建的协程是消费者。 它们随机睡眠0~1秒的时间,然后从LIFO队列stack中取出 24 | # 第一个元素是name的元组。 25 | async def comsumer(stack, sem, name): 26 | while True: 27 | t = random.random() 28 | await asyncio.sleep(t) 29 | #申请获得信号量,当计数器值为0时被挂起,否则使计数器减1。 30 | await sem.acquire() 31 | #取出数据项。 32 | data = stack.pop() 33 | print(f"{name}: pop ({data[0]}, {data[1]})") 34 | print(f" stack size: {len(stack)}") 35 | 36 | 37 | async def main(): 38 | #创建生产者和消费者共享的LIFO队列。 39 | q = list() 40 | #创建信号量。 41 | s = asyncio.Semaphore(0) 42 | #创建生产者任务。 43 | p1 = asyncio.create_task(producer(q, s, "p1")) 44 | p2 = asyncio.create_task(producer(q, s, "p2")) 45 | #创建消费者任务。 46 | c1 = asyncio.create_task(comsumer(q, s, "c1")) 47 | c2 = asyncio.create_task(comsumer(q, s, "c2")) 48 | c3 = asyncio.create_task(comsumer(q, s, "c3")) 49 | #将多个任务聚集成一个。 50 | task = asyncio.gather(p1, p2, c1, c2, c3) 51 | #task = asyncio.gather(p1, p2, c1) 52 | try: 53 | #启动任务,运行5秒。 54 | await asyncio.wait_for(task, 5) 55 | except asyncio.TimeoutError: 56 | #取消任务。 57 | task.cancel() 58 | sys.exit(0) 59 | 60 | 61 | if __name__ == '__main__': 62 | asyncio.run(main()) 63 | -------------------------------------------------------------------------------- /代码/coroutine21.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | 8 | async def producer(stack, sem1, sem2, name): 9 | while True: 10 | t = random.random() 11 | await asyncio.sleep(t) 12 | n = random.randrange(100) 13 | #申请获得限制生产者的信号量。 14 | await sem1.acquire() 15 | stack.append((name, n)) 16 | print(f"append ({name}, {n})") 17 | print(f" stack size: {len(stack)}") 18 | #释放限制消费者的信号量。 19 | sem2.release() 20 | 21 | 22 | async def comsumer(stack, sem1, sem2, name): 23 | while True: 24 | t = random.random() 25 | await asyncio.sleep(t) 26 | #申请获得限制消费者的信号量。 27 | await sem2.acquire() 28 | data = stack.pop() 29 | print(f"{name}: pop ({data[0]}, {data[1]})") 30 | print(f" stack size: {len(stack)}") 31 | #释放限制生产者的信号量。 32 | sem1.release() 33 | 34 | 35 | async def main(): 36 | q = list() 37 | #创建限制生产者的信号量,其计数器的初始值是4。 38 | s1 = asyncio.Semaphore(4) 39 | #创建限制消费者的信号量,其计数器的初始值是0。 40 | s2 = asyncio.Semaphore(0) 41 | #创建生产者任务。 42 | p1 = asyncio.create_task(producer(q, s1, s2, "p1")) 43 | p2 = asyncio.create_task(producer(q, s1, s2, "p2")) 44 | #创建消费者任务。 45 | c1 = asyncio.create_task(comsumer(q, s1, s2, "c1")) 46 | task = asyncio.gather(p1, p2, c1) 47 | try: 48 | await asyncio.wait_for(task, 5) 49 | except asyncio.TimeoutError: 50 | task.cancel() 51 | sys.exit(0) 52 | 53 | 54 | if __name__ == '__main__': 55 | asyncio.run(main()) 56 | -------------------------------------------------------------------------------- /代码/coroutine22.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | 8 | async def producer(stack, sem, name): 9 | while True: 10 | t = random.random() 11 | await asyncio.sleep(t) 12 | try: 13 | n = random.randrange(100) 14 | stack.append((name, n)) 15 | #该操作可能导致抛出ValueError异常。 16 | sem.release() 17 | print(f"append ({name}, {n})") 18 | except ValueError: 19 | #如果抛出了ValueError异常,则丢弃生成的数据项。 20 | stack.pop() 21 | print(f"fail to append ({name}, {n})") 22 | finally: 23 | print(f" stack size: {len(stack)}") 24 | 25 | 26 | async def comsumer(stack, sem, name): 27 | while True: 28 | t = random.random() 29 | await asyncio.sleep(t) 30 | await sem.acquire() 31 | data = stack.pop() 32 | print(f"{name}: pop ({data[0]}, {data[1]})") 33 | print(f" stack size: {len(stack)}") 34 | 35 | 36 | async def main(): 37 | #被生产者和消费者共享的FIFO队列初始就被填满。 38 | q = [("init", -1), ("init", -2), ("init", -3), ("init", -4)] 39 | #创建限制消费者的受限信号量,其初始值和最大值都是4。 40 | s = asyncio.BoundedSemaphore(4) 41 | #创建生产者任务。 42 | p1 = asyncio.create_task(producer(q, s, "p1")) 43 | p2 = asyncio.create_task(producer(q, s, "p2")) 44 | #创建消费者任务。 45 | c1 = asyncio.create_task(comsumer(q, s, "c1")) 46 | task = asyncio.gather(p1, p2, c1) 47 | try: 48 | await asyncio.wait_for(task, 5) 49 | except asyncio.TimeoutError: 50 | task.cancel() 51 | sys.exit(0) 52 | 53 | 54 | if __name__ == '__main__': 55 | asyncio.run(main()) 56 | -------------------------------------------------------------------------------- /代码/coroutine23.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | #被读者和写者共享的资源。 8 | resource = ['*', '$', '#'] 9 | 10 | 11 | #该协程函数创建的协程为写者。 它们会用data中的元素按顺序依次替换resource中的三个元素, 12 | # 每次替换前随机等待0~1秒,替换后显示操作成功相关信息。 13 | async def writer(data, name): 14 | global resource 15 | for i in range(3): 16 | t = random.random() 17 | await asyncio.sleep(t) 18 | resource[i] = data[i] 19 | print(f"{name}: write {data[i]}, now {resource[0] + resource[1] + resource[2]}") 20 | 21 | 22 | #该协程函数创建的协程为读者。 它们会按顺序依次读取resource中的三个元素,每次读取前随机 23 | # 等待0~1秒,读取后显示操作成功相关信息。 24 | async def reader(name): 25 | global resource 26 | for i in range(3): 27 | t = random.random() 28 | await asyncio.sleep(t) 29 | print(f"{name}: read {resource[i]}") 30 | 31 | 32 | async def main(): 33 | #定义4个读者和2个写者,按照r1,w1,r2,r3,w2,r4的顺序执行读写操作。 34 | r1 = asyncio.create_task(reader("r1")) 35 | w1 = asyncio.create_task(writer("abc", "w1")) 36 | r2 = asyncio.create_task(reader("r2")) 37 | r3 = asyncio.create_task(reader("r3")) 38 | w2 = asyncio.create_task(writer("def", "w2")) 39 | r4 = asyncio.create_task(reader("r4")) 40 | await asyncio.gather(r1, w1, r2, r3, w2, r4) 41 | sys.exit(0) 42 | 43 | 44 | if __name__ == '__main__': 45 | asyncio.run(main()) 46 | -------------------------------------------------------------------------------- /代码/coroutine24.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | resource = ['*', '$', '#'] 8 | #资源锁,在进行读操作和写操作期间都需要一直持有该锁。 9 | resource_lock = asyncio.Lock() 10 | #记录当前读者数量的计数器。 11 | read_count = 0 12 | 13 | 14 | async def writer(data, name): 15 | global resource, resource_lock 16 | #申请获得资源锁。 17 | await resource_lock.acquire() 18 | for i in range(3): 19 | t = random.random() 20 | await asyncio.sleep(t) 21 | resource[i] = data[i] 22 | print(f"{name}: write {data[i]}, now {resource[0] + resource[1] + resource[2]}") 23 | #释放资源锁。 24 | resource_lock.release() 25 | 26 | 27 | async def reader(name): 28 | global resource, resource_lock, read_count 29 | #读者的数量加1。 30 | read_count = read_count + 1 31 | #如果该读者是第一个,则申请获得资源锁。 32 | if read_count == 1: 33 | await resource_lock.acquire() 34 | for i in range(3): 35 | t = random.random() 36 | await asyncio.sleep(t) 37 | print(f"{name}: read {resource[i]}") 38 | #读者的数量减1。 39 | read_count = read_count - 1 40 | #如果该读者是最后一个,则释放资源锁。 41 | if read_count == 0: 42 | resource_lock.release() 43 | 44 | 45 | async def main(): 46 | r1 = asyncio.create_task(reader("r1")) 47 | w1 = asyncio.create_task(writer("abc", "w1")) 48 | r2 = asyncio.create_task(reader("r2")) 49 | r3 = asyncio.create_task(reader("r3")) 50 | w2 = asyncio.create_task(writer("def", "w2")) 51 | r4 = asyncio.create_task(reader("r4")) 52 | await asyncio.gather(r1, w1, r2, r3, w2, r4) 53 | sys.exit(0) 54 | 55 | 56 | if __name__ == '__main__': 57 | asyncio.run(main()) 58 | -------------------------------------------------------------------------------- /代码/coroutine25.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | resource = ['*', '$', '#'] 8 | resource_lock = asyncio.Lock() 9 | #写保护锁,在执行写操作期间需要一直持有该锁。 而在执行读操作时先要获得该锁,在获得 10 | # 资源锁后释放。 11 | write_lock = asyncio.Lock() 12 | read_count = 0 13 | #记录当前写者数量的计数器。 14 | write_count = 0 15 | 16 | 17 | async def writer(data, name): 18 | global resource, resource_lock, write_lock, write_count 19 | #写者的数量加1。 20 | write_count = write_count + 1 21 | #如果该写者是第一个,则申请获得写保护锁。 22 | if write_count == 1: 23 | await write_lock.acquire() 24 | await resource_lock.acquire() 25 | for i in range(3): 26 | t = random.random() 27 | await asyncio.sleep(t) 28 | resource[i] = data[i] 29 | print(f"{name}: write {data[i]}, now {resource[0] + resource[1] + resource[2]}") 30 | resource_lock.release() 31 | #写者的数量减1。 32 | write_count = write_count - 1 33 | #如果该写者是最后一个,则释放写保护锁。 34 | if write_count == 0: 35 | write_lock.release() 36 | 37 | 38 | async def reader(name): 39 | global resource, resource_lock, read_count, write_lock 40 | #申请获得写保护锁。 41 | await write_lock.acquire() 42 | read_count = read_count + 1 43 | if read_count == 1: 44 | await resource_lock.acquire() 45 | #释放写保护锁。 46 | write_lock.release() 47 | for i in range(3): 48 | t = random.random() 49 | await asyncio.sleep(t) 50 | print(f"{name}: read {resource[i]}") 51 | read_count = read_count - 1 52 | if read_count == 0: 53 | resource_lock.release() 54 | 55 | 56 | async def main(): 57 | r1 = asyncio.create_task(reader("r1")) 58 | w1 = asyncio.create_task(writer("abc", "w1")) 59 | r2 = asyncio.create_task(reader("r2")) 60 | r3 = asyncio.create_task(reader("r3")) 61 | w2 = asyncio.create_task(writer("def", "w2")) 62 | r4 = asyncio.create_task(reader("r4")) 63 | await asyncio.gather(r1, w1, r2, r3, w2, r4) 64 | sys.exit(0) 65 | 66 | 67 | if __name__ == '__main__': 68 | asyncio.run(main()) 69 | -------------------------------------------------------------------------------- /代码/coroutine26.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | resource = ['*', '$', '#'] 8 | resource_lock = asyncio.Lock() 9 | #排队锁,不论执行读操作还是写操作都要先获得该锁,在获得资源锁后释放。 10 | queue_lock = asyncio.Lock() 11 | read_count = 0 12 | 13 | 14 | async def writer(data, name): 15 | global resource, resource_lock, queue_lock 16 | #申请获得排队锁。 17 | await queue_lock.acquire() 18 | await resource_lock.acquire() 19 | #释放排队锁。 20 | queue_lock.release() 21 | for i in range(3): 22 | t = random.random() 23 | await asyncio.sleep(t) 24 | resource[i] = data[i] 25 | print(f"{name}: write {data[i]}, now {resource[0] + resource[1] + resource[2]}") 26 | resource_lock.release() 27 | 28 | 29 | async def reader(name): 30 | global resource, resource_lock, read_count, queue_lock 31 | #申请获得排队锁。 32 | await queue_lock.acquire() 33 | read_count = read_count + 1 34 | if read_count == 1: 35 | await resource_lock.acquire() 36 | #释放排队锁。 37 | queue_lock.release() 38 | for i in range(3): 39 | t = random.random() 40 | await asyncio.sleep(t) 41 | print(f"{name}: read {resource[i]}") 42 | read_count = read_count - 1 43 | if read_count == 0: 44 | resource_lock.release() 45 | 46 | 47 | async def main(): 48 | r1 = asyncio.create_task(reader("r1")) 49 | w1 = asyncio.create_task(writer("abc", "w1")) 50 | r2 = asyncio.create_task(reader("r2")) 51 | r3 = asyncio.create_task(reader("r3")) 52 | w2 = asyncio.create_task(writer("def", "w2")) 53 | r4 = asyncio.create_task(reader("r4")) 54 | await asyncio.gather(r1, w1, r2, r3, w2, r4) 55 | sys.exit(0) 56 | 57 | 58 | if __name__ == '__main__': 59 | asyncio.run(main()) 60 | -------------------------------------------------------------------------------- /代码/coroutine27.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | lock1 = asyncio.Lock() 8 | lock2 = asyncio.Lock() 9 | 10 | 11 | #该协程函数创建的协程显示“foo”之前必须同时获得lock1和lock2。 12 | async def foo(): 13 | #先申请获得lock1。 14 | await lock1.acquire() 15 | #挂起一瞬间。 16 | await asyncio.sleep(0) 17 | #再申请获得lock2。 18 | await lock2.acquire() 19 | print("foo") 20 | lock2.release() 21 | lock1.release() 22 | 23 | 24 | #该协程函数创建的协程显示“bar”之前必须同时获得lock2和lock1。 25 | async def bar(): 26 | #先申请获得lock2。 27 | await lock2.acquire() 28 | #挂起一瞬间。 29 | await asyncio.sleep(0) 30 | #再申请获得lock1。 31 | await lock1.acquire() 32 | print("bar") 33 | lock1.release() 34 | lock2.release() 35 | 36 | 37 | async def main(): 38 | print("begin") 39 | await asyncio.gather(foo(), bar()) 40 | print("end") 41 | sys.exit(0) 42 | 43 | 44 | if __name__ == '__main__': 45 | asyncio.run(main()) 46 | -------------------------------------------------------------------------------- /代码/coroutine28.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | #该函数创建指定类型的异步队列,然后以同步方式用指定的数据将其填满,最后再以同步方式取 7 | #出所有数据。 队列的状态变化会被显示。 8 | def dynamic_queue(data, priority, quetype="Queue"): 9 | #创建指定类型的异步队列,容量都是3。 10 | if quetype == "PriorityQueue": 11 | q = asyncio.PriorityQueue(3) 12 | print("\nq is a priority queue:") 13 | elif quetype == "LifoQueue": 14 | q = asyncio.LifoQueue(3) 15 | print("\nq is a LIFO queue (stack):") 16 | else: 17 | q = asyncio.Queue(3) 18 | print("\nq is a FIFO queue:") 19 | #显示队列的初始状态: 20 | print(f"q.maxsize == {q.maxsize}") 21 | print(f"q.empty() == {q.empty()}") 22 | #用指定的数据填满队列: 23 | n = 0 24 | while True: 25 | try: 26 | #对于FIFO队列和LIfO队列来说,数据项是一个元组。 对于优先级队列来说, 27 | # 元组的第一个元素是优先级,第二个元素才是数据项。 28 | q.put_nowait((priority[n], data[n])) 29 | print(f"q.qsize() == {q.qsize()}") 30 | n = n + 1 31 | #抛出asyncio.QueueFull异常说明队列已满。 32 | except asyncio.QueueFull: 33 | print(f"q.full() == {q.full()}") 34 | break 35 | #取出所有数据: 36 | while True: 37 | try: 38 | d = q.get_nowait() 39 | print(d) 40 | print(f"q.qsize() == {q.qsize()}") 41 | #抛出asyncio.QueueEmpty异常说明队列已空。 42 | except asyncio.QueueEmpty: 43 | print(f"q.empty() == {q.empty()}") 44 | break 45 | 46 | 47 | def main(): 48 | #准备好数据和优先级。 49 | data = 'abcd' 50 | priority = (20, 30, 10, 40) 51 | print(f'Data is "{data}".') 52 | print(f"Priorities is {priority}.") 53 | #验证队列的性质。 54 | dynamic_queue(data, priority) 55 | #验证栈的性质。 56 | dynamic_queue(data, priority, "LifoQueue") 57 | #验证优先级队列的性质。 58 | dynamic_queue(data, priority, "PriorityQueue") 59 | return 0 60 | 61 | 62 | if __name__ == '__main__': 63 | sys.exit(main()) 64 | -------------------------------------------------------------------------------- /代码/coroutine29.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | 8 | #该协程函数创建的协程是生产者。 它们每隔0.5秒随机生成一个0~100内的整数,并将其插入 9 | # 异步队列。 10 | async def producer(queue): 11 | while True: 12 | n = random.randrange(100) 13 | await queue.put(n) 14 | await asyncio.sleep(0.5) 15 | 16 | 17 | #该协程函数创建的协程是消费者。 它们不停地从异步队列取出整数,并检查其是否是7的倍数, 18 | # 如果是则抛出记录有尝试次数消息的Exception异常。 19 | async def consumer(queue): 20 | trial = 0 21 | while True: 22 | trial = trial + 1 23 | n = await queue.get() 24 | sys.stdout.write(str(n) + " ") 25 | sys.stdout.flush() 26 | if n % 7 == 0: 27 | raise Exception(f"Found after {trial} trials!") 28 | 29 | 30 | async def main(): 31 | #创建生产者和消费者共享的异步队列。 32 | q = asyncio.Queue() 33 | #创建生产者任务。 34 | p_task = asyncio.create_task(producer(q)) 35 | #创建消费者任务。 36 | c_task = asyncio.create_task(consumer(q)) 37 | try: 38 | #启动任务。 39 | await asyncio.gather(p_task, c_task) 40 | except Exception as e: 41 | #取消任务。 42 | p_task.cancel() 43 | c_task.cancel() 44 | #显示异常携带的消息。 45 | print("\n" + e.args[0]) 46 | sys.exit(0) 47 | 48 | 49 | if __name__ == '__main__': 50 | asyncio.run(main()) 51 | -------------------------------------------------------------------------------- /代码/coroutine3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | 7 | async def stopwatch(sec): 8 | n = 0 9 | while n < sec: 10 | sys.stdout.write(str(sec - n) + ' ') 11 | sys.stdout.flush() 12 | n = await asyncio.sleep(1, n + 1) 13 | sys.stdout.write('0\n') 14 | sys.stdout.flush() 15 | 16 | 17 | async def main(): 18 | if len(sys.argv) < 2: 19 | sys.exit(1) 20 | try: 21 | sec = int(sys.argv[1]) 22 | await stopwatch(sec) 23 | sys.exit(0) 24 | except Exception: 25 | sys.exit(1) 26 | 27 | 28 | #使用Runner对象代替asyncio.run()函数。 29 | if __name__ == '__main__': 30 | with asyncio.Runner() as runner: 31 | runner.run(main()) 32 | -------------------------------------------------------------------------------- /代码/coroutine30.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import random 5 | import sys 6 | 7 | 8 | #该协程函数创建的协程是生产者。 它们不停地随机生成一个0~100内的整数,并将其插入 9 | # 异步队列。 当队列变满时,它会挂起自身直到队列被清空。 10 | async def producer(queue): 11 | while True: 12 | try: 13 | n = random.randrange(100) 14 | queue.put_nowait(n) 15 | except asyncio.QueueFull: 16 | await queue.join() 17 | 18 | 19 | #该协程函数创建的协程是消费者。 它们每隔0.5秒从异步队列取出整数,并检查其是否是7的 20 | # 倍数,如果是则抛出记录有尝试次数消息的Exception异常。 21 | async def comsumer(queue): 22 | trial = 0 23 | while True: 24 | trial = trial + 1 25 | n = await queue.get() 26 | #取出数据项后一定要通知异步队列。 27 | queue.task_done() 28 | sys.stdout.write(str(n) + " ") 29 | sys.stdout.flush() 30 | if n % 7 == 0: 31 | raise Exception(f"Found after {trial} trials!") 32 | await asyncio.sleep(0.5) 33 | 34 | 35 | async def main(): 36 | #创建生产者和消费者共享的异步队列,其容量是5。 37 | q = asyncio.LifoQueue(5) 38 | p_task = asyncio.create_task(producer(q)) 39 | c_task = asyncio.create_task(comsumer(q)) 40 | try: 41 | await asyncio.gather(p_task, c_task) 42 | except Exception as e: 43 | p_task.cancel() 44 | c_task.cancel() 45 | print("\n" + e.args[0]) 46 | sys.exit(0) 47 | 48 | 49 | if __name__ == '__main__': 50 | asyncio.run(main()) 51 | -------------------------------------------------------------------------------- /代码/coroutine31.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | #指定服务器绑定的IP地址。 7 | host = '127.0.0.1' 8 | #指定服务器监听的TCP端口。 9 | port = 8000 10 | 11 | 12 | #定义处理连接请求的协程函数。 13 | async def echo(reader, writer): 14 | #在TCP连接成功建立后,可以一直响应客户发来的消息,并将消息反射给客户,直到收到特殊 15 | # 消息“quit”。 16 | while True: 17 | #异步读取一行二进制数据,注意这会包含\n。 18 | data = await reader.readline() 19 | #将二进制数据转换为文本消息。 20 | msg = data.decode() 21 | #将文本消息再次转换为二进制数据。 22 | data = msg.encode() 23 | #将二进制数据原封不动地异步写入。 24 | writer.write(data) 25 | #如果读取到的文本消息是“quit”,则退出循环。 26 | if msg == "quit\n": 27 | break 28 | #关闭异步流。 29 | writer.close() 30 | 31 | 32 | async def main(): 33 | #创建服务器,并绑定到指定的IP,在指定的TCP端口上监听。 服务器被创建后并未启动。 34 | server = await asyncio.start_server(echo, host, port, start_serving=False) 35 | #创建服务器的控制任务。 36 | controller = asyncio.create_task(server.serve_forever()) 37 | try: 38 | #启动并运行服务器60秒。 39 | await asyncio.wait_for(controller, 60) 40 | except asyncio.TimeoutError: 41 | #60秒后自动关闭服务器。 42 | controller.cancel() 43 | sys.exit(0) 44 | 45 | 46 | if __name__ == '__main__': 47 | asyncio.run(main()) 48 | -------------------------------------------------------------------------------- /代码/coroutine32.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | #指定服务器的IP地址。 7 | host = '127.0.0.1' 8 | #指定服务器的TCP端口。 9 | port = 8000 10 | 11 | 12 | async def main(): 13 | #建立到服务器的TCP连接,并获得相关异步流的读取器和写入器。 14 | reader, writer = await asyncio.open_connection(host, port) 15 | #在TCP连接成功建立后,可以一直向服务器发送消息,并将反射来的消息通过标准输出显示, 16 | # 直到发送了特殊消息“quit”。 17 | while True: 18 | #让用户随意输入一行文本,注意这不会包含\n。 19 | text = input('You can send any message to the server, "quit" to stop: ') 20 | #给文本添加\n以形成文本消息。 21 | msg = text + "\n" 22 | #将文本消息转换为二进制数据。 23 | data = msg.encode() 24 | #将二进制数据异步写入。 25 | writer.write(data) 26 | #异步读取一行二进制数据,注意这会包含\n。 27 | data = await reader.readline() 28 | #将二进制数据转换为文本消息。 29 | msg = data.decode() 30 | #显示文本消息。 31 | print(msg) 32 | #如果读取到的文本消息是“quit”,则退出循环。 33 | if msg == "quit\n": 34 | break 35 | #关闭异步流。 36 | writer.close() 37 | sys.exit(0) 38 | 39 | 40 | if __name__ == '__main__': 41 | asyncio.run(main()) 42 | -------------------------------------------------------------------------------- /代码/coroutine33.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | host = '127.0.0.1' 7 | port = 8001 8 | 9 | 10 | async def engine(reader, writer): 11 | while True: 12 | #从异步流读取“(command, message)”格式的二进制数据。 13 | binary = await reader.readuntil(b")") 14 | #将二进制数据转换为文本数据。 15 | text = binary.decode().strip() 16 | #从文本数据中抽取命令和消息。 17 | command, _, message = text.partition(",") 18 | command = command.strip("( ") 19 | message = message.strip(") ") 20 | #根据命令对消息做不同的处理。 21 | match command.lower(): 22 | case "upper": 23 | message = message.upper() 24 | case "lower": 25 | message = message.lower() 26 | case "swapcase": 27 | message = message.swapcase() 28 | case "capitalize": 29 | message = message.capitalize() 30 | case "title": 31 | message = message.title() 32 | case "quit": 33 | message = "quit" 34 | case _: 35 | message = "unknown command." 36 | #基于消息生成文本数据。 37 | text = message + "\n" 38 | #将文本数据转换为二进制数据。 39 | binary = text.encode() 40 | #将二进制数据写入异步流。 41 | writer.write(binary) 42 | if message == "quit": 43 | break 44 | writer.close() 45 | 46 | 47 | async def main(): 48 | #创建服务器,并让其自动启动。 49 | server = await asyncio.start_server(engine, host, port) 50 | #等待60秒。 51 | await asyncio.sleep(60) 52 | #关闭服务器。 53 | server.close() 54 | sys.exit(0) 55 | 56 | 57 | if __name__ == '__main__': 58 | asyncio.run(main()) 59 | -------------------------------------------------------------------------------- /代码/coroutine34.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | host = '127.0.0.1' 7 | port = 8001 8 | 9 | 10 | async def main(): 11 | reader, writer = await asyncio.open_connection(host, port) 12 | while True: 13 | text = input('Input a "(command, message)" style request, "(quit,)" to stop: ') 14 | #将文本数据转换为二进制数据,不需要添加\n。 15 | data = text.encode() 16 | writer.write(data) 17 | data = await reader.readline() 18 | msg = data.decode() 19 | print(msg) 20 | if msg == "quit\n": 21 | break 22 | writer.close() 23 | sys.exit(0) 24 | 25 | 26 | if __name__ == '__main__': 27 | asyncio.run(main()) 28 | -------------------------------------------------------------------------------- /代码/coroutine35.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | #指定实现Unix套接字的文件。 7 | path = "unix_socks/temporary.sock" 8 | 9 | 10 | async def echo(reader, writer): 11 | while True: 12 | data = await reader.readline() 13 | msg = data.decode() 14 | data = msg.encode() 15 | writer.write(data) 16 | if msg == "quit\n": 17 | break 18 | writer.close() 19 | 20 | 21 | async def main(): 22 | #创建服务器,并指定使用的Unix套接字。 23 | server = await asyncio.start_unix_server(echo, path, start_serving=False) 24 | controller = asyncio.create_task(server.serve_forever()) 25 | try: 26 | await asyncio.wait_for(controller, 60) 27 | except asyncio.TimeoutError: 28 | controller.cancel() 29 | sys.exit(0) 30 | 31 | 32 | if __name__ == '__main__': 33 | asyncio.run(main()) 34 | -------------------------------------------------------------------------------- /代码/coroutine36.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | #指定实现Unix套接字的文件。 7 | path = "unix_socks/temporary.sock" 8 | 9 | 10 | async def main(): 11 | #建立到服务器的Unix套接字连接,并获得相关异步流的读取器和写入器。 12 | reader, writer = await asyncio.open_unix_connection(path) 13 | while True: 14 | text = input('You can send any message to the server, "quit" to stop: ') 15 | msg = text + "\n" 16 | data = msg.encode() 17 | writer.write(data) 18 | data = await reader.readline() 19 | msg = data.decode() 20 | print(msg) 21 | if msg == "quit\n": 22 | break 23 | writer.close() 24 | sys.exit(0) 25 | 26 | 27 | if __name__ == '__main__': 28 | asyncio.run(main()) 29 | -------------------------------------------------------------------------------- /代码/coroutine37.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import time 5 | import sys 6 | 7 | 8 | #该函数模拟需要执行阻塞I/O的函数。 9 | def blocked_io(oprand1, oprand2, operator): 10 | #阻塞3秒。 11 | time.sleep(3) 12 | return eval(str(oprand1) + str(operator) + str(oprand2)) 13 | 14 | 15 | async def main(): 16 | print(f'start at {time.strftime("%X")}.') 17 | #创建四个线程分别执行blocked_io()的一次调用。 18 | coro1 = asyncio.to_thread(blocked_io, 35, 17, "+") 19 | coro2 = asyncio.to_thread(blocked_io, 35, 17, "-") 20 | coro3 = asyncio.to_thread(blocked_io, 35, 17, "*") 21 | coro4 = asyncio.to_thread(blocked_io, 35, 17, "/") 22 | #使这四个线程并行执行。 23 | result = await asyncio.gather(coro1, coro2, coro3, coro4) 24 | print(f'{time.strftime("%X")}: 35+17={result[0]}') 25 | print(f'{time.strftime("%X")}: 35-17={result[1]}') 26 | print(f'{time.strftime("%X")}: 35*17={result[2]}') 27 | print(f'{time.strftime("%X")}: 35/17={result[3]}') 28 | sys.exit(0) 29 | 30 | if __name__ == '__main__': 31 | asyncio.run(main()) 32 | -------------------------------------------------------------------------------- /代码/coroutine38.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import io 4 | import time 5 | import sys 6 | 7 | 8 | #主函数先睡眠3秒,然后将第一个命令行参数指定的文件的内容拷贝到第二个命令行参数指定的 9 | # 文件。 10 | def main(): 11 | time.sleep(3) 12 | if len(sys.argv) < 3: 13 | #如果命令行参数少于2个,则通过标准出错报错。 14 | sys.stderr.write("Not enough arguments.\n") 15 | sys.stderr.flush() 16 | return 1 17 | try: 18 | source = io.FileIO(sys.argv[1]) 19 | target = io.FileIO(sys.argv[2], 'w') 20 | pair = io.BufferedRWPair(source, target) 21 | content = pair.read(10) 22 | while content: 23 | pair.write(content) 24 | content = pair.read(10) 25 | pair.close() 26 | #如果拷贝成功,则通过标准输出给出提示信息。 27 | sys.stdout.write(f"Successfully copy from {sys.argv[1]} to {sys.argv[2]}.\n") 28 | sys.stdout.flush() 29 | except Exception as e: 30 | #如果抛出了异常,则通过标准出错报错。 31 | sys.stderr.write(repr(e) + "\n") 32 | sys.stderr.flush() 33 | return 2 34 | return 0 35 | 36 | if __name__ == '__main__': 37 | sys.exit(main()) 38 | -------------------------------------------------------------------------------- /代码/coroutine39.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import time 5 | import sys 6 | 7 | 8 | async def main(): 9 | #显示开始执行的时间。 10 | print(f'start at {time.strftime("%X")}.') 11 | #创建三个子进程分别以不同的参数执行coroutine38.py。 子进程proc1将a1.txt拷贝 12 | # 到b1.txt。 13 | proc1 = await asyncio.create_subprocess_exec("./coroutine38.py", "a1.txt", "b1.txt") 14 | #proc1 = await asyncio.create_subprocess_shell("./coroutine38.py a1.txt b1.txt") 15 | #子进程proc2将a2.txt拷贝到b2.txt。 16 | proc2 = await asyncio.create_subprocess_exec("./coroutine38.py", "a2.txt", "b2.txt") 17 | #proc2 = await asyncio.create_subprocess_shell("./coroutine38.py a2.txt b2.txt") 18 | #子进程proc3将a3.txt拷贝到b3.txt。 19 | proc3 = await asyncio.create_subprocess_exec("./coroutine38.py", "a3.txt", "b3.txt") 20 | #proc3 = await asyncio.create_subprocess_shell("./coroutine38.py a3.txt b3.txt") 21 | #等待三个子进程都执行完成。 22 | result = await asyncio.gather(proc1.wait(), proc2.wait(), proc3.wait(), return_exceptions=True) 23 | #显示三个子进程的退出状态。 24 | print(result) 25 | #显示执行完成的时间。 26 | print(f'end at {time.strftime("%X")}.') 27 | sys.exit(0) 28 | 29 | if __name__ == '__main__': 30 | asyncio.run(main()) 31 | -------------------------------------------------------------------------------- /代码/coroutine4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | #本脚本以同步编程的方式实现coroutine1.py的功能。 4 | 5 | import time 6 | import sys 7 | 8 | 9 | #该函数代表秒表。 sec参数传入需计时的秒数。 10 | def stopwatch(sec): 11 | n = 0 12 | while n < sec: 13 | sys.stdout.write(str(sec - n) + ' ') 14 | sys.stdout.flush() 15 | #强制等待1秒钟。 16 | time.sleep(1) 17 | n = n + 1 18 | sys.stdout.write('0\n') 19 | sys.stdout.flush() 20 | 21 | 22 | #主函数将第一个命令行参数解读为需计时的秒数。 23 | def main(): 24 | if len(sys.argv) < 2: 25 | return 1 26 | try: 27 | sec = int(sys.argv[1]) 28 | #stopwatch()是以同步方式运行的。 29 | stopwatch(sec) 30 | return 0 31 | except Exception: 32 | return 1 33 | 34 | 35 | #调用主函数。 36 | if __name__ == '__main__': 37 | sys.exit(main()) 38 | -------------------------------------------------------------------------------- /代码/coroutine40.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | 5 | 6 | #该程序判断一个正整数是否是质数。 7 | def main(): 8 | while True: 9 | try: 10 | #从标准输入读取整数。 11 | n = int(input()) 12 | if n < 0: 13 | raise RuntimeError() 14 | if n == 0 or n == 1: 15 | #将结果写入标准输出。 16 | print(f"{n} is not a prime.") 17 | continue 18 | for m in range(2, n): 19 | if n % m == 0: 20 | #将结果写入标准输出。 21 | print(f"{n} is not a prime, it equals {n//m}*{m}.") 22 | break 23 | #将结果写入标准输出。 24 | if m == n-1: 25 | print(f"{n} is a prime.") 26 | except Exception: 27 | #将错误信息写入标准出错。 28 | sys.stderr.write("Only accept natural number or -1!\n") 29 | sys.stderr.flush() 30 | return 0 31 | 32 | if __name__ == '__main__': 33 | sys.exit(main()) 34 | -------------------------------------------------------------------------------- /代码/coroutine41.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | async def console(proc): 7 | while True: 8 | try: 9 | #从标准输入读取数据。 10 | data = input("Please enter a natural number, -1 means quit: ") 11 | #当读取到-1时终止程序。 12 | if data == "-1": 13 | print("Closed!") 14 | #向子进程的标准输入写入EOF。 15 | proc.stdin.write_eof() 16 | try: 17 | #先尝试正常终止子进程。 18 | proc.terminate() 19 | except Exception: 20 | #杀死子进程。 21 | proc.kill() 22 | #跳出循环,终止程序。 23 | break 24 | #将读取到的数据写入子进程的标准输入。 25 | proc.stdin.write((data + "\n").encode()) 26 | #创建一个任务从子进程的标准输出中读取一行。 27 | task1 = asyncio.create_task(proc.stdout.readline()) 28 | #创建一个任务从子进程的标准出错中读取一行。 29 | task2 = asyncio.create_task(proc.stderr.readline()) 30 | #等待两个任务之一完成。 31 | done, pending = await asyncio.wait([task1, task2], return_when=asyncio.FIRST_COMPLETED) 32 | #输出子进程返回的信息。 33 | for task in done: 34 | print(task.result().decode()) 35 | #取消尚未完成的任务。 36 | for task in pending: 37 | task.cancel() 38 | except Exception as e: 39 | print(repr(e)) 40 | return 0 41 | 42 | 43 | async def main(): 44 | #创建一个子进程执行coroutine40.py。 45 | proc = await asyncio.create_subprocess_exec("./coroutine40.py", stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 46 | #proc = await asyncio.create_subprocess_shell("./coroutine40.py", stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 47 | #将控制该子进程的Process对象传给console,创建相应协程并等待。 48 | await console(proc) 49 | sys.exit(0) 50 | 51 | if __name__ == '__main__': 52 | asyncio.run(main()) 53 | -------------------------------------------------------------------------------- /代码/coroutine42.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #改写自coroutine15.py 3 | 4 | import asyncio 5 | import random 6 | import time 7 | import sys 8 | 9 | 10 | async def hiker(name, barrier): 11 | try: 12 | t = random.uniform(0.5, 7.0) 13 | await asyncio.sleep(t) 14 | print(f"{name}: I meet the barrier at {time.strftime('%X')}.") 15 | print(f"{name}: n_waiting == {barrier.n_waiting}, broken == {barrier.broken}") 16 | #以异步上下文管理器的方式使用屏障。 17 | async with barrier: 18 | print(f"{name}: I cross the barrier at {time.strftime('%X')}.") 19 | print(f"{name}: n_waiting == {barrier.n_waiting}, broken == {barrier.broken}") 20 | except asyncio.BrokenBarrierError: 21 | print(f"{name}: The barrier collapses before {time.strftime('%X')}. Hooray!") 22 | print(f"{name}: n_waiting == {barrier.n_waiting}, broken == {barrier.broken}") 23 | 24 | 25 | async def hammer(barrier): 26 | await asyncio.sleep(5) 27 | await barrier.abort() 28 | #await barrier.reset() 29 | 30 | 31 | async def main(): 32 | barrier = asyncio.Barrier(3) 33 | hiker1 = asyncio.create_task(hiker("hiker1", barrier)) 34 | hiker2 = asyncio.create_task(hiker("hiker2", barrier)) 35 | hiker3 = asyncio.create_task(hiker("hiker3", barrier)) 36 | hammer0 = asyncio.create_task(hammer(barrier)) 37 | print(f"Start at {time.strftime('%X')}") 38 | await asyncio.gather(hiker1, hiker2, hiker3, hammer0) 39 | sys.exit(0) 40 | 41 | 42 | if __name__ == '__main__': 43 | asyncio.run(main()) 44 | -------------------------------------------------------------------------------- /代码/coroutine43.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #改写自coroutine17.py 3 | 4 | import asyncio 5 | import sys 6 | 7 | 8 | async def stars(lock): 9 | while True: 10 | #将锁当成异步上下文管理器来使用。 11 | async with lock: 12 | print(f"\nstars: locked == {lock.locked()}") 13 | for i in range(3): 14 | await asyncio.sleep(0.1) 15 | sys.stdout.write("*") 16 | sys.stdout.flush() 17 | 18 | 19 | async def dollars(lock): 20 | while True: 21 | #将锁当成异步上下文管理器来使用。 22 | async with lock: 23 | print(f"\ndollars: locked == {lock.locked()}") 24 | for i in range(3): 25 | await asyncio.sleep(0.1) 26 | sys.stdout.write("$") 27 | sys.stdout.flush() 28 | 29 | 30 | async def main(): 31 | lock = asyncio.Lock() 32 | task_stars = asyncio.create_task(stars(lock)) 33 | task_dollars = asyncio.create_task(dollars(lock)) 34 | task = asyncio.gather(task_stars, task_dollars) 35 | try: 36 | print(f"\nlocked == {lock.locked()}") 37 | await asyncio.wait_for(task, 1.1) 38 | except asyncio.TimeoutError: 39 | print(f"\n\nlocked == {lock.locked()}") 40 | sys.exit(0) 41 | 42 | 43 | if __name__ == '__main__': 44 | asyncio.run(main()) 45 | -------------------------------------------------------------------------------- /代码/coroutine44.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #改写自coroutine18.py 3 | 4 | import asyncio 5 | import random 6 | import sys 7 | 8 | 9 | async def stars(cond): 10 | #将监视器当成异步上下文管理器来使用。 11 | async with cond: 12 | while True: 13 | await cond.wait() 14 | for i in range(3): 15 | await asyncio.sleep(0.1) 16 | sys.stdout.write("*") 17 | sys.stdout.flush() 18 | print("") 19 | 20 | 21 | async def dollars(cond): 22 | #将监视器当成异步上下文管理器来使用。 23 | async with cond: 24 | while True: 25 | await cond.wait() 26 | for i in range(3): 27 | await asyncio.sleep(0.1) 28 | sys.stdout.write("$") 29 | sys.stdout.flush() 30 | print("") 31 | 32 | 33 | async def num_gen(lock, cond1, cond2): 34 | while True: 35 | #将锁当成异步上下文管理器来使用。 36 | async with lock: 37 | n = random.randrange(100) 38 | if n % 2 == 0: 39 | cond1.notify() 40 | else: 41 | cond2.notify() 42 | await asyncio.sleep(0) 43 | 44 | 45 | async def main(): 46 | lock = asyncio.Lock() 47 | cond1 = asyncio.Condition(lock) 48 | cond2 = asyncio.Condition(lock) 49 | task_num_gen = asyncio.create_task(num_gen(lock, cond1, cond2)) 50 | task_stars = asyncio.create_task(stars(cond1)) 51 | task_dollars = asyncio.create_task(dollars(cond2)) 52 | task = asyncio.gather(task_num_gen, task_stars, task_dollars) 53 | try: 54 | await asyncio.wait_for(task, 2) 55 | except asyncio.TimeoutError: 56 | pass 57 | sys.exit(0) 58 | 59 | 60 | if __name__ == '__main__': 61 | asyncio.run(main()) 62 | -------------------------------------------------------------------------------- /代码/coroutine45.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #改写自coroutine19.py 3 | 4 | import asyncio 5 | import random 6 | import time 7 | import sys 8 | 9 | even_number = None 10 | 11 | 12 | async def stars(cond): 13 | while True: 14 | #将监视器当成异步上下文管理器来使用。 15 | async with cond: 16 | await cond.wait_for(lambda: even_number) 17 | for i in range(3): 18 | await asyncio.sleep(0.1) 19 | sys.stdout.write("*") 20 | sys.stdout.flush() 21 | print("") 22 | 23 | 24 | async def dollars(cond): 25 | while True: 26 | #将监视器当成异步上下文管理器来使用。 27 | async with cond: 28 | await cond.wait_for(lambda: not even_number) 29 | for i in range(3): 30 | await asyncio.sleep(0.1) 31 | sys.stdout.write("$") 32 | sys.stdout.flush() 33 | print("") 34 | 35 | 36 | async def num_gen(cond): 37 | global even_number 38 | while True: 39 | #将监视器当成异步上下文管理器来使用。 40 | async with cond: 41 | n = random.randrange(100) 42 | if n % 2 == 0: 43 | even_number = True 44 | else: 45 | even_number = False 46 | cond.notify_all() 47 | await asyncio.sleep(0) 48 | 49 | 50 | async def main(): 51 | cond = asyncio.Condition() 52 | task_num_gen = asyncio.create_task(num_gen(cond)) 53 | task_stars = asyncio.create_task(stars(cond)) 54 | task_dollars = asyncio.create_task(dollars(cond)) 55 | task = asyncio.gather(task_num_gen, task_stars, task_dollars) 56 | try: 57 | await asyncio.wait_for(task, 2) 58 | except asyncio.TimeoutError: 59 | pass 60 | sys.exit(0) 61 | 62 | 63 | if __name__ == '__main__': 64 | asyncio.run(main()) 65 | -------------------------------------------------------------------------------- /代码/coroutine46.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #改写自coroutine33.py 3 | 4 | import asyncio 5 | import sys 6 | 7 | host = '127.0.0.1' 8 | port = 8001 9 | 10 | 11 | async def engine(reader, writer): 12 | while True: 13 | binary = await reader.readuntil(b")") 14 | text = binary.decode().strip() 15 | command, _, message = text.partition(",") 16 | command = command.strip("( ") 17 | message = message.strip(") ") 18 | match command.lower(): 19 | case "upper": 20 | message = message.upper() 21 | case "lower": 22 | message = message.lower() 23 | case "swapcase": 24 | message = message.swapcase() 25 | case "capitalize": 26 | message = message.capitalize() 27 | case "title": 28 | message = message.title() 29 | case "quit": 30 | message = "quit" 31 | case _: 32 | message = "unknown command." 33 | text = message + "\n" 34 | binary = text.encode() 35 | writer.write(binary) 36 | if message == "quit": 37 | break 38 | writer.close() 39 | 40 | 41 | async def main(): 42 | server = await asyncio.start_server(engine, host, port) 43 | #将Server对象当成异步上下文管理器来使用。 44 | async with server: 45 | await asyncio.sleep(60) 46 | 47 | 48 | if __name__ == '__main__': 49 | asyncio.run(main()) 50 | -------------------------------------------------------------------------------- /代码/coroutine5.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import time 5 | import sys 6 | 7 | #引用主协程的全局变量。 8 | coro_main = None 9 | 10 | 11 | #该协程函数创建的协程会显示自身的执行过程。 它会睡眠1秒,在睡眠前后分别输出提示信息。 12 | # 它还会显示主协程的cr_await属性的当前值。 13 | async def self_explain(tag): 14 | print(f"{tag}: sleep at {time.strftime('%X')}") 15 | await asyncio.sleep(1) 16 | print(f"{tag}: awake at {time.strftime('%X')}") 17 | print(f" {tag}: " + str(coro_main.cr_await)) 18 | 19 | 20 | #主协程函数混合使用了协程和任务。 21 | async def main(): 22 | await self_explain("coro1") 23 | task1 = asyncio.create_task(self_explain("task1")) 24 | task2 = asyncio.create_task(self_explain("task2")) 25 | await task2 26 | await self_explain("coro2") 27 | task3 = asyncio.create_task(self_explain("task3")) 28 | await task1 29 | await self_explain("coro3") 30 | await task3 31 | sys.exit(0) 32 | 33 | 34 | if __name__ == '__main__': 35 | coro_main = main() 36 | asyncio.run(coro_main) 37 | -------------------------------------------------------------------------------- /代码/coroutine6.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import time 5 | import sys 6 | 7 | 8 | #该任务将通过msg传入的消息在延迟sec秒后写入标准输出。 9 | async def delayed_sender(sec, msg, tag): 10 | try: 11 | await asyncio.sleep(sec) 12 | print(f"{tag}: {msg} at {time.strftime('%X')}") 13 | except asyncio.CancelledError as e: 14 | print(f"{tag}: Sending message is cancelled at {time.strftime('%X')}.") 15 | print(e.args) 16 | #raise 17 | 18 | 19 | async def main(): 20 | task1 = asyncio.create_task(delayed_sender(1, "Message1", "sender1")) 21 | task2 = asyncio.create_task(delayed_sender(2, "Message2", "sender2")) 22 | task3 = asyncio.create_task(delayed_sender(3, "Message3", "sender3")) 23 | #开始并行执行任务队列中的三个任务。 24 | await asyncio.sleep(0.5) 25 | #取消task2。 26 | task2.cancel("Cancelling task2 ...") 27 | await task1 28 | await task2 29 | await task3 30 | sys.exit(0) 31 | 32 | 33 | if __name__ == '__main__': 34 | asyncio.run(main()) 35 | -------------------------------------------------------------------------------- /代码/coroutine7.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | 7 | #该任务基于正整数n生成一个数列并写入标准输出。 8 | async def seq_gen(n): 9 | try: 10 | #终止条件是n小于等于0。 11 | while n > 0: 12 | sys.stdout.write(str(n) + " ") 13 | sys.stdout.flush() 14 | #如果n是19的倍数,则抛出RuntimeError异常。 15 | if n % 19 == 0: 16 | raise RuntimeError() 17 | #如果n是11的倍数,则取消该任务。 18 | if n % 11 == 0: 19 | #调用自身的cancel()。 20 | asyncio.current_task().cancel() 21 | #数列的推导公式是a(n) = int(a(n-1)/7) - 1。 22 | n = n // 7 - 1 23 | await asyncio.sleep(1) 24 | finally: 25 | print("\n") 26 | return n 27 | 28 | 29 | #该函数通过访问任务的属性获得任务相关信息。 30 | def show_task_result(task): 31 | #确定任务的当前状态。 32 | print("task.cancelled() ==", task.cancelled()) 33 | print("task.done() ==", task.done()) 34 | try: 35 | #取得任务的结果,注意这可能导致抛出异常。 36 | print("task.result() ==", task.result()) 37 | print("task.exception() ==", task.exception()) 38 | except BaseException as e: 39 | print("task.result() ==", repr(e)) 40 | print("task.exception() ==", repr(e)) 41 | 42 | 43 | #主协程函数将第一个命令行参数视为数列的起始项。 44 | async def main(): 45 | if len(sys.argv) < 2: 46 | sys.exit(1) 47 | try: 48 | n = int(sys.argv[1]) 49 | task = asyncio.create_task(seq_gen(n)) 50 | await task 51 | except (asyncio.CancelledError, RuntimeError): 52 | #数列未完全生成。 53 | print("The sequence is truncated!") 54 | show_task_result(task) 55 | except Exception: 56 | sys.exit(1) 57 | else: 58 | #数列完全生成。 59 | print("The sequence is fully generated.") 60 | show_task_result(task) 61 | sys.exit(0) 62 | 63 | 64 | if __name__ == '__main__': 65 | asyncio.run(main()) 66 | -------------------------------------------------------------------------------- /代码/coroutine8.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | #引用两个子任务的全局变量。 7 | task1 = None 8 | task2 = None 9 | 10 | 11 | #该协程函数用于输出平方表的自变量。 12 | async def n(bound): 13 | for i in range(bound): 14 | print('n:', i) 15 | await asyncio.sleep(1) 16 | 17 | 18 | #该协程函数用于输出平方表的因变量。 19 | async def n_square(bound): 20 | for i in range(bound): 21 | print('n square:', i * i) 22 | await asyncio.sleep(1) 23 | 24 | 25 | #该协程函数输出平方表,并将前两个协程函数作为子任务。 26 | async def print_square_table(bound): 27 | #global task1, task2 28 | global task1, task2 29 | #try: 30 | task1 = asyncio.create_task(n(bound)) 31 | task2 = asyncio.create_task(n_square(bound)) 32 | await task1 33 | await task2 34 | #await asyncio.shield(task1) 35 | #await asyncio.shield(task2) 36 | #except asyncio.CancelledError: 37 | #task1.cancel() 38 | #task2.cancel() 39 | #raise 40 | 41 | 42 | #该协程函数在2.9秒后取消输出平方表的任务。 43 | async def cancel_print(task): 44 | await asyncio.sleep(2.9) 45 | task.cancel() 46 | 47 | 48 | #主协程函数将第一个命令行参数解读为输出到平方表的第几项。 49 | async def main(): 50 | global task1, task2 51 | if len(sys.argv) < 2: 52 | sys.exit(1) 53 | try: 54 | bound = int(sys.argv[1]) 55 | #创建输出平方表的任务。 56 | task = asyncio.create_task(print_square_table(bound)) 57 | #创建取消输出平方表的任务。 58 | cancel_task = asyncio.create_task(cancel_print(task)) 59 | await task 60 | await cancel_task 61 | except asyncio.CancelledError: 62 | pass 63 | #在接收到asyncio.CancelledError后显示输出平方表的任务和它的两个子任务的当前 64 | # 状态。 65 | print("task.cancelled():", task.cancelled()) 66 | print("task.done():", task.done()) 67 | print("task1.cancelled():", task1.cancelled()) 68 | print("task1.done():", task1.done()) 69 | print("task2.cancelled():", task2.cancelled()) 70 | print("task2.done():", task2.done()) 71 | #让主协程持续运行到task1和task2的状态都变成“已完成”或“已取消”。 72 | while not task1.done() or not task2.done(): 73 | await asyncio.sleep(1) 74 | sys.exit(0) 75 | 76 | 77 | if __name__ == '__main__': 78 | asyncio.run(main()) 79 | -------------------------------------------------------------------------------- /代码/coroutine9.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import asyncio 4 | import sys 5 | 6 | task1 = None 7 | task2 = None 8 | 9 | 10 | async def n(bound): 11 | for i in range(bound): 12 | print('n:', i) 13 | await asyncio.sleep(1) 14 | 15 | 16 | async def n_square(bound): 17 | for i in range(bound): 18 | print('n square:', i * i) 19 | await asyncio.sleep(1) 20 | 21 | 22 | async def print_square_table(bound): 23 | global task1, task2 24 | try: 25 | task1 = asyncio.create_task(n(bound)) 26 | task2 = asyncio.create_task(n_square(bound)) 27 | await task1 28 | await task2 29 | except asyncio.CancelledError: 30 | task1.cancel() 31 | task2.cancel() 32 | raise 33 | 34 | 35 | async def main(): 36 | global task1, task2 37 | if len(sys.argv) < 2: 38 | sys.exit(1) 39 | try: 40 | bound = int(sys.argv[1]) 41 | task = asyncio.create_task(print_square_table(bound)) 42 | #使得等待task完成的时间不超过2.9秒。 43 | waited_task = asyncio.wait_for(task, 2.9) 44 | await waited_task 45 | #这里需要处理的是asyncio.TimeoutError异常而非asyncio.CancelledError异常。 46 | except asyncio.TimeoutError: 47 | pass 48 | print("task.cancelled():", task.cancelled()) 49 | print("task.done():", task.done()) 50 | print("task1.cancelled():", task1.cancelled()) 51 | print("task1.done():", task1.done()) 52 | print("task2.cancelled():", task2.cancelled()) 53 | print("task2.done():", task2.done()) 54 | while not task1.done() or not task2.done(): 55 | await asyncio.sleep(1) 56 | sys.exit(0) 57 | 58 | 59 | if __name__ == '__main__': 60 | asyncio.run(main()) 61 | -------------------------------------------------------------------------------- /代码/debug1.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | 4 | def fibonacci(n): 5 | if __debug__: 6 | #这里是调试用的代码,以跟踪递归过程。 7 | print('fibo(' + str(n) + ')') 8 | if n < 2: 9 | return 1 10 | else: 11 | return fibonacci(n-1) + fibonacci(n-2) 12 | 13 | 14 | @functools.cache 15 | def fibonacci_cache(n): 16 | if __debug__: 17 | #这里是调试用的代码,以跟踪递归过程。 18 | print('fibo(' + str(n) + ')') 19 | if n < 2: 20 | return 1 21 | else: 22 | return fibonacci_cache(n-1) + fibonacci_cache(n-2) 23 | 24 | -------------------------------------------------------------------------------- /代码/debug2.py: -------------------------------------------------------------------------------- 1 | s = "********" 2 | n = 0 3 | while n < 5: 4 | n = n + 1 5 | #这里断言n不超过4。 6 | assert n < 5 7 | print(s[0:n]) 8 | 9 | -------------------------------------------------------------------------------- /代码/debug3.py: -------------------------------------------------------------------------------- 1 | import functools, sys 2 | 3 | 4 | #自定义审计钩子。 5 | def myaudithook(event, parameters): 6 | if event == 'fibo': 7 | print('fibo(' + str(parameters[0]) +')') 8 | 9 | 10 | #注册审计钩子。 11 | sys.addaudithook(myaudithook) 12 | 13 | 14 | def fibonacci(n): 15 | #触发自定义审计事件。 16 | sys.audit('fibo', n) 17 | if n < 2: 18 | return 1 19 | else: 20 | return fibonacci(n-1) + fibonacci(n-2) 21 | 22 | 23 | @functools.cache 24 | def fibonacci_cache(n): 25 | #触发自定义审计事件。 26 | sys.audit('fibo', n) 27 | if n < 2: 28 | return 1 29 | else: 30 | return fibonacci_cache(n-1) + fibonacci_cache(n-2) 31 | 32 | -------------------------------------------------------------------------------- /代码/debug4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | #这是一个用来阐述如何进行调试的Python脚本。 4 | 5 | """This module illustrates how to debug with pdb. 6 | 7 | In this module, two functions to calculate factorial are defined, one uses loop and the other uses recursion. 8 | """ 9 | 10 | import sys, pdb 11 | 12 | __all__ = ['factorial1', 'factorial2'] 13 | 14 | 15 | #这是一个通过循环实现阶乘的函数。 16 | def factorial1(n): 17 | """This function calculates n! using loop.""" 18 | 19 | product = 1 20 | while n > 1: 21 | #pdb.set_trace(header="start loop") 22 | product = product * n 23 | n = n-1 24 | return product 25 | 26 | 27 | #这是一个通过递归实现阶乘的函数。 28 | def factorial2(n): 29 | """This function calculates n! using recursion.""" 30 | 31 | #breakpoint() 32 | if n > 1: 33 | return n * factorial2(n-1) 34 | else: 35 | return 1 36 | 37 | 38 | #入口点函数。 39 | def main(): 40 | """This function is called when this script runs in the top-level environment.""" 41 | 42 | result = factorial1(3) 43 | print(result) 44 | result = factorial2(3) 45 | print(result) 46 | 47 | return 0 48 | 49 | 50 | #判断脚本是否在顶层环境中运行。 51 | if __name__ == '__main__': 52 | sys.exit(main()) 53 | -------------------------------------------------------------------------------- /代码/demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | #这是一个用于展示规范格式的Python脚本。 4 | 5 | """This module defines a factorial sequence generator. 6 | 7 | The function factorial_sequence() generate the sequence and return it as a list. 8 | 9 | When runs as the main module, it asks the user to enter an integer, then print the according factorial sequence. 10 | """ 11 | 12 | import sys 13 | import re 14 | 15 | __all__ = ['factorial_sequence'] 16 | 17 | 18 | #该函数根据参数n生成序列[1!, 2!, ..., n!]。 19 | def factorial_sequence(n): 20 | """This function is the factorial sequence generator.""" 21 | 22 | l = [] 23 | i = 1 24 | factorial = 1 25 | 26 | while i <= n: 27 | factorial = factorial * i 28 | i = i + 1 29 | l.append(factorial) 30 | 31 | return l 32 | 33 | 34 | #入口点函数。 35 | def main(): 36 | """This function is called when this script runs in the top-level environment.""" 37 | 38 | print("这是一个生成阶乘序列的工具。输入“quit”退出。\n") 39 | 40 | while True: 41 | s = input("请输入一个正整数:") 42 | if s == "quit": 43 | break 44 | if re.match(r"^[1-9][0-9]*$", s): 45 | n = int(s) 46 | print(factorial_sequence(n)) 47 | else: 48 | print("您输入的并非正整数。") 49 | 50 | return 0 51 | 52 | 53 | #判断脚本是否在顶层环境中被执行。 54 | if __name__ == '__main__': 55 | sys.exit(main()) 56 | 57 | 58 | -------------------------------------------------------------------------------- /代码/demo/__init__.py: -------------------------------------------------------------------------------- 1 | # 这是一个用于展示规范格式的包。 2 | 3 | """This packet contains a factorial sequence generator. 4 | 5 | The function factorial_sequence() generate the sequence and return it as a list. 6 | 7 | When runs as the main module, it asks the user to enter an integer, then print the according factorial sequence. 8 | """ 9 | 10 | __all__ = ['factorial_sequence'] 11 | 12 | from .factorial_sequence import * 13 | -------------------------------------------------------------------------------- /代码/demo/__main__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from .main import main 3 | 4 | #判断包是否在顶层环境中运行。 5 | if __name__ == '__main__': 6 | sys.exit(main()) 7 | 8 | -------------------------------------------------------------------------------- /代码/demo/factorial_sequence.py: -------------------------------------------------------------------------------- 1 | #该函数根据参数n生成序列[1!, 2!, ..., n!]。 2 | def factorial_sequence(n): 3 | """This function is the factorial sequence generator.""" 4 | 5 | l = [] 6 | i = 1 7 | factorial = 1 8 | 9 | while i <= n: 10 | factorial = factorial * i 11 | i = i + 1 12 | l.append(factorial) 13 | 14 | return l 15 | 16 | -------------------------------------------------------------------------------- /代码/demo/main.py: -------------------------------------------------------------------------------- 1 | import re 2 | from .factorial_sequence import * 3 | 4 | #入口点函数。 5 | def main(): 6 | """This function is called when this script runs in the top-level environment.""" 7 | 8 | print("这是一个生成阶乘序列的工具。输入“quit”退出。\n") 9 | 10 | while True: 11 | s = input("请输入一个正整数:") 12 | if s == "quit": 13 | break 14 | if re.match(r"^[1-9][0-9]*$", s): 15 | n = int(s) 16 | print(factorial_sequence(n)) 17 | else: 18 | print("您输入的并非正整数。") 19 | 20 | return 0 21 | 22 | -------------------------------------------------------------------------------- /代码/dir1/__init__.py: -------------------------------------------------------------------------------- 1 | from .a import A1 2 | 3 | #__all__ = ['a', 'b'] 4 | -------------------------------------------------------------------------------- /代码/dir1/a.py: -------------------------------------------------------------------------------- 1 | A1 = 1 2 | A2 = 2 3 | -------------------------------------------------------------------------------- /代码/dir1/b.py: -------------------------------------------------------------------------------- 1 | B3 = 3 2 | B4 = 4 3 | -------------------------------------------------------------------------------- /代码/dir1/dir2/__init__.py: -------------------------------------------------------------------------------- 1 | from .c import C5, C6 2 | 3 | -------------------------------------------------------------------------------- /代码/dir1/dir2/c.py: -------------------------------------------------------------------------------- 1 | C5 = 5 2 | C6 = 6 3 | -------------------------------------------------------------------------------- /代码/dir1/dir2/dir3/__init__.py: -------------------------------------------------------------------------------- 1 | from .d import D7, D8 2 | 3 | -------------------------------------------------------------------------------- /代码/dir1/dir2/dir3/d.py: -------------------------------------------------------------------------------- 1 | D7 = 7 2 | D8 = 8 3 | -------------------------------------------------------------------------------- /代码/dir1/dir4/__init__.py: -------------------------------------------------------------------------------- 1 | position = __path__[0] 2 | __path__ = [position, position + '/dir5'] 3 | 4 | from .e import E9, E10 5 | from .f import F11, F12 6 | from ..dir2.dir3 import D7 7 | -------------------------------------------------------------------------------- /代码/dir1/dir4/dir5/f.py: -------------------------------------------------------------------------------- 1 | F11 = 11 2 | F12 = 12 3 | -------------------------------------------------------------------------------- /代码/dir1/dir4/e.py: -------------------------------------------------------------------------------- 1 | E9 = 9 2 | E10 = 10 3 | 4 | -------------------------------------------------------------------------------- /代码/docstring.py: -------------------------------------------------------------------------------- 1 | """This module illustrates how docstrings work. 2 | 3 | In this module, one function f and one class C are defined, each of which has a docstring. C also has one method, which also has a docstring. And here is the docstring for the whole module. 4 | """ 5 | 6 | 7 | def f(): 8 | """This function does nothing. """ 9 | pass 10 | 11 | 12 | class C(): 13 | """This class does nothing. 14 | 15 | It has no public methods and attributes. 16 | 17 | And no public instance attributes are defined. 18 | """ 19 | 20 | def __init__(self): 21 | """When initializing this class, no arguments are needed.""" 22 | pass 23 | 24 | 25 | -------------------------------------------------------------------------------- /代码/encapsulation1.py: -------------------------------------------------------------------------------- 1 | class Grade: 2 | #实例属性_value的取值范围是1~5,只能取整数。 3 | def __init__(self, v): 4 | v = int(v) 5 | if v > 5: 6 | v = 5 7 | if v < 1: 8 | v = 1 9 | self._value = v 10 | 11 | #读取_value属性的方法。 12 | def getV(self): 13 | return self._value 14 | 15 | #设置_value属性的方法。 用同__init__的方法确保取值范围是1~5,只能取整数。 16 | def setV(self, v): 17 | v = int(v) 18 | if v > 5: 19 | v = 5 20 | if v < 1: 21 | v = 1 22 | self._value = v 23 | 24 | #删除_value属性的方法。 直接返回以禁止删除_value。 25 | def deleteV(self): 26 | return 27 | 28 | -------------------------------------------------------------------------------- /代码/encapsulation2.py: -------------------------------------------------------------------------------- 1 | #此数据描述器用于保证托管属性引用一个浮点数。 2 | class FloatValidator: 3 | #用该描述器本身的实例属性managed储存被托管属性的名称_name。 而name就是引用该 4 | # 描述器的公有属性的名称。 5 | def __set_name__(self, owner, name): 6 | self.managed = '_' + name 7 | 8 | #当通过实例读取name属性时,转化为读取_name属性。 当通过类对象读取name属性时, 9 | # 返回描述器本身。 读取到的浮点数保留两位小数。 10 | def __get__(self, instance, owner=None): 11 | if instance is None: 12 | return self 13 | else: 14 | value = getattr(instance, self.managed, NotImplemented) 15 | if value is not NotImplemented: 16 | value = round(value, 2) 17 | return value 18 | 19 | #当通过实例设置name属性时,转化为设置_name属性。 设置时要保证赋值浮点数,默认 20 | # 为0.0。 21 | def __set__(self, instance, value): 22 | try: 23 | value = float(value) 24 | except ValueError: 25 | value = 0.0 26 | setattr(instance, self.managed, value) 27 | 28 | #当通过实例删除name属性时,转化为删除_name属性。 29 | def __delete__(self, instance): 30 | delattr(instance, self.managed) 31 | 32 | 33 | class Person: 34 | #访问托管属性_height的接口。 35 | height = FloatValidator() 36 | 37 | #访问托管属性_weight的接口。 38 | weight = FloatValidator() 39 | 40 | #初始化。 41 | def __init__(self, h, w): 42 | self.height = h 43 | self.weight = w 44 | 45 | 46 | class Wallet: 47 | #访问托管属性_coin的接口。 48 | amount = FloatValidator() 49 | 50 | #初始化。 51 | def __init__(self): 52 | self.amount = 0.0 53 | 54 | -------------------------------------------------------------------------------- /代码/encapsulation3.py: -------------------------------------------------------------------------------- 1 | class Wallet: 2 | #在初始化时设置被托管的私有属性。 3 | def __init__(self): 4 | self._amount = 0.0 5 | 6 | #传入fget的函数。 7 | def get_amount(self): 8 | if self._amount is not NotImplemented: 9 | return round(self._amount, 2) 10 | else: 11 | return self._amount 12 | 13 | #传入fset的函数。 14 | def set_amount(self, value): 15 | try: 16 | value = float(value) 17 | except ValueError: 18 | value = 0.0 19 | self._amount = value 20 | 21 | #传入fdel的函数。 22 | def del_amount(self): 23 | self._amount = NotImplemented 24 | 25 | #作为访问私有属性接口的公有属性。 26 | amount = property(get_amount, set_amount, del_amount) 27 | 28 | -------------------------------------------------------------------------------- /代码/encapsulation4.py: -------------------------------------------------------------------------------- 1 | class Wallet: 2 | def __init__(self): 3 | self._amount = 0.0 4 | 5 | #在定义作为访问私有属性接口的公有属性的同时实现了fget。 6 | @property 7 | def amount(self): 8 | if self._amount is not NotImplemented: 9 | return round(self._amount, 2) 10 | else: 11 | return self._amount 12 | 13 | #更新fset。 14 | @amount.setter 15 | def amount(self, value): 16 | try: 17 | value = float(value) 18 | except ValueError: 19 | value = 0.0 20 | self._amount = value 21 | 22 | #更新fdel。 23 | @amount.deleter 24 | def amount(self): 25 | self._amount = NotImplemented 26 | 27 | -------------------------------------------------------------------------------- /代码/encapsulation5.py: -------------------------------------------------------------------------------- 1 | import time 2 | import functools 3 | 4 | 5 | class CachedFibonacci: 6 | #以实例属性储存斐波拉契序列的索引。 7 | def __init__(self, i): 8 | self.index = i 9 | 10 | #斐波拉契序列生成器,私有类属性。 11 | def __fibonacci(self, n): 12 | if n < 2: 13 | return 1 14 | else: 15 | return self.__fibonacci(n-1) + self.__fibonacci(n-2) 16 | 17 | #基于实例属性动态生成斐波拉契序列的元素。 这虽然是一个类属性,但通过不同实例访 18 | # 问得到不同的值。 19 | @functools.cached_property 20 | def element(self): 21 | return self.__fibonacci(self.index) 22 | 23 | 24 | #定义一个统计访问CachedFibonacci实例的element属性所需时间的函数。 25 | def process_time(cf): 26 | starttime = time.time() 27 | print('element: ' + str(cf.element)) 28 | endtime = time.time() 29 | print('time: ' + str(endtime - starttime)) 30 | 31 | -------------------------------------------------------------------------------- /代码/eval.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | a = 15 4 | b = 6 5 | c = 79 6 | 7 | while True: 8 | expr = input("请输入一个以a、b和c中的两个作为参数的四则运算式(输入空串终止):") 9 | if expr: 10 | if re.match(r"^[abc][\+\-\*\/][abc]$", expr): 11 | d = eval(expr) 12 | print(expr + "的结果为" + str(d) + "。") 13 | else: 14 | print("请输入正确的运算式!") 15 | else: 16 | break 17 | 18 | -------------------------------------------------------------------------------- /代码/exception1.py: -------------------------------------------------------------------------------- 1 | def f(a): 2 | return 'str:' + a 3 | 4 | f(1) 5 | -------------------------------------------------------------------------------- /代码/exception10.py: -------------------------------------------------------------------------------- 1 | print("这是一个判断整数符号的小游戏。\n") 2 | 3 | while True: 4 | try: 5 | s = input("请输入一个整数:") 6 | if s == "quit": 7 | print("你已经退出了游戏。\n") 8 | break 9 | n = int(s) 10 | except ValueError: 11 | print("您输入的并非整数。") 12 | except Exception: 13 | print("发生了未知错误。") 14 | else: 15 | if n < 0: 16 | print("这是一个负数。") 17 | elif n > 0: 18 | print("这是一个正数。") 19 | else: 20 | print("这是零。") 21 | 22 | -------------------------------------------------------------------------------- /代码/exception11.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | 5 | def f(x, y): 6 | try: 7 | result = math.nan 8 | result = math.sqrt(x)/y 9 | except TypeError: 10 | print('Please enter two numbers!') 11 | except ValueError: 12 | print('x must be non-negative!') 13 | finally: 14 | print(sys.exc_info()) 15 | return result 16 | -------------------------------------------------------------------------------- /代码/exception12.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def f(x, y): 5 | try: 6 | result = math.nan 7 | result = math.sqrt(x)/y 8 | finally: 9 | return result 10 | -------------------------------------------------------------------------------- /代码/exception2.py: -------------------------------------------------------------------------------- 1 | def f(a): 2 | try: 3 | return 'str:' + a 4 | except TypeError: 5 | return 'str:Please enter a string!' 6 | -------------------------------------------------------------------------------- /代码/exception3.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def f(x, y): 5 | try: 6 | return math.sqrt(x)/y 7 | except TypeError: 8 | print('Please enter two numbers!') 9 | return math.nan 10 | except ValueError: 11 | print('x must be non-negative!') 12 | return math.nan 13 | except ZeroDivisionError: 14 | print('y cannot be 0!') 15 | return math.nan 16 | -------------------------------------------------------------------------------- /代码/exception4.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def f(x, y): 5 | try: 6 | return math.sqrt(x)/y 7 | except (TypeError, ValueError, ZeroDivisionError): 8 | return math.nan 9 | -------------------------------------------------------------------------------- /代码/exception5.py: -------------------------------------------------------------------------------- 1 | import math 2 | import time 3 | 4 | 5 | def f(x, y): 6 | try: 7 | return math.sqrt(x)/y 8 | except (TypeError, ValueError, ZeroDivisionError) as e: 9 | t = time.asctime() 10 | fd = open('err.log', 'a') 11 | fd.writelines(( 12 | 'time: ' + t + '\n', 13 | 'type: ' + repr(type(e)) + '\n', 14 | 'args: ' + repr(e.args) + '\n', 15 | '\n')) 16 | fd.close() 17 | return math.nan 18 | -------------------------------------------------------------------------------- /代码/exception6.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | c = 'c' 5 | 6 | def f(x, y): 7 | global c 8 | a = 'a' 9 | try: 10 | b = 'b' 11 | return math.sqrt(x)/y 12 | except TypeError as a: 13 | print(a) 14 | return math.nan 15 | except ValueError as b: 16 | print(b) 17 | return math.nan 18 | except ZeroDivisionError as c: 19 | print(c) 20 | return math.nan 21 | finally: 22 | print(a) 23 | print(b) 24 | print(c) 25 | 26 | -------------------------------------------------------------------------------- /代码/exception7.py: -------------------------------------------------------------------------------- 1 | import math 2 | import time 3 | import sys 4 | 5 | 6 | def f(x, y): 7 | try: 8 | return math.sqrt(x)/y 9 | except (TypeError, ValueError, ZeroDivisionError): 10 | t = time.asctime() 11 | ty, v, tb = sys.exc_info() 12 | cursor = tb 13 | tb_info = '' 14 | while cursor is not None: 15 | tb_info = tb_info + repr(cursor.tb_frame) + '\n' 16 | cursor = cursor.tb_next 17 | fd = open('err.log', 'a') 18 | fd.writelines(( 19 | 'time: ' + t + '\n', 20 | 'type: ' + repr(ty) + '\n', 21 | 'args: ' + repr(v.args) + '\n', 22 | 'traceback:\n', 23 | tb_info, 24 | '\n')) 25 | fd.close() 26 | return math.nan 27 | -------------------------------------------------------------------------------- /代码/exception8.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def f(x, y): 5 | try: 6 | return math.exp(x)/y 7 | except ZeroDivisionError: 8 | print("Divisor cannot be 0.") 9 | return math.nan 10 | except ArithmeticError: 11 | print("Unknown arithmetic error.") 12 | return math.nan 13 | -------------------------------------------------------------------------------- /代码/exception9.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def f(x, y): 5 | try: 6 | return math.exp(x)/y 7 | except ArithmeticError: 8 | print("Unknown arithmetic error.") 9 | return math.nan 10 | except ZeroDivisionError: 11 | print("Divisor cannot be 0.") 12 | return math.nan 13 | -------------------------------------------------------------------------------- /代码/exception_group.py: -------------------------------------------------------------------------------- 1 | #该函数接收一个异常组,将其自动抛出,然后以except子句对异常组进行处理。 2 | def eg_handler(eg): 3 | try: 4 | raise(eg) 5 | except ExceptionGroup as e: 6 | print("An ExceptionGroup!") 7 | print(e.message) 8 | n = len(e.exceptions) 9 | i = 0 10 | while i < n: 11 | print(repr(e.exceptions[i])) 12 | i = i + 1 13 | except BaseExceptionGroup as e: 14 | print("An BaseExceptionGroup!") 15 | print(e.message) 16 | n = len(e.exceptions) 17 | i = 0 18 | while i < n: 19 | print(repr(e.exceptions[i])) 20 | i = i + 1 21 | return None 22 | -------------------------------------------------------------------------------- /代码/exec.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | a = 15 4 | b = 6 5 | c = 79 6 | 7 | while True: 8 | expr = input("请输入一个以a、b和c中的两个作为参数的四则运算式(输入空串终止):") 9 | if expr: 10 | if re.match(r"^[abc][\+\-\*\/][abc]$", expr): 11 | code = 'print("' + expr + '的结果为" + str(' + expr + ') + "。")' 12 | exec(code) 13 | else: 14 | print("请输入正确的运算式!") 15 | else: 16 | break 17 | 18 | -------------------------------------------------------------------------------- /代码/factorial1.py: -------------------------------------------------------------------------------- 1 | #这是一个通过递归实现阶乘的函数。 2 | def factorial(n): 3 | if n > 1: 4 | return n * factorial(n-1) 5 | else: 6 | return 1 7 | -------------------------------------------------------------------------------- /代码/factorial2.py: -------------------------------------------------------------------------------- 1 | #这是一个通过循环实现阶乘的函数。 2 | def factorial(n): 3 | product = 1 4 | 5 | while n > 1: 6 | product = product*n 7 | n = n-1 8 | 9 | return product 10 | -------------------------------------------------------------------------------- /代码/flags.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | print(sys.flags) 4 | -------------------------------------------------------------------------------- /代码/function_decorator1.py: -------------------------------------------------------------------------------- 1 | #定义被用作装饰器的函数。 2 | def mydecorator(wrapped): 3 | def wrapper(*args, **kwargs): 4 | print("I can do anything before calling the target!") 5 | result = wrapped(*args, **kwargs) 6 | print("I can do anything after calling the target!") 7 | return result 8 | return wrapper 9 | 10 | 11 | #定义目标函数1。 12 | def mytarget1(): 13 | print("I am doing nothing.") 14 | return 0 15 | 16 | 17 | #定义目标函数2。 18 | def mytarget2(obj): 19 | print("I am doing the truth value testing.") 20 | return bool(obj) 21 | 22 | 23 | #定义目标函数3。 24 | def mytarget3(x, y): 25 | print("I am an adder.") 26 | return float(x) + float(y) 27 | 28 | 29 | #定义目标函数4。 30 | def mytarget4(*substr): 31 | print("I am an concatenator.") 32 | length = len(substr) 33 | if length == 0: 34 | return '' 35 | elif length == 1: 36 | return substr[0] 37 | else: 38 | i = 0 39 | s = '' 40 | while i < length: 41 | s = s + substr[i] 42 | i = i + 1 43 | return s 44 | 45 | 46 | #对目标函数1进行装饰。 47 | mytarget1 = mydecorator(mytarget1) 48 | 49 | #对目标函数2进行装饰。 50 | mytarget2 = mydecorator(mytarget2) 51 | 52 | #对目标函数3进行装饰。 53 | mytarget3 = mydecorator(mytarget3) 54 | 55 | #对目标函数4进行装饰。 56 | mytarget4 = mydecorator(mytarget4) 57 | 58 | -------------------------------------------------------------------------------- /代码/function_decorator2.py: -------------------------------------------------------------------------------- 1 | def mydecorator(wrapped): 2 | def wrapper(*args, **kwargs): 3 | print("I can do anything before calling the target!") 4 | result = wrapped(*args, **kwargs) 5 | print("I can do anything after calling the target!") 6 | return result 7 | return wrapper 8 | 9 | 10 | #定义目标函数1,同时完成装饰。 11 | @mydecorator 12 | def mytarget1(): 13 | print("I am doing nothing.") 14 | return 0 15 | 16 | 17 | #定义目标函数2,同时完成装饰。 18 | @mydecorator 19 | def mytarget2(obj): 20 | print("I am doing the truth value testing.") 21 | return bool(obj) 22 | 23 | 24 | #定义目标函数3,同时完成装饰。 25 | @mydecorator 26 | def mytarget3(x, y): 27 | print("I am an adder.") 28 | return float(x) + float(y) 29 | 30 | 31 | #定义目标函数4,同时完成装饰。 32 | @mydecorator 33 | def mytarget4(*substr): 34 | print("I am an concatenator.") 35 | length = len(substr) 36 | if length == 0: 37 | return '' 38 | elif length == 1: 39 | return substr[0] 40 | else: 41 | i = 0 42 | s = '' 43 | while i < length: 44 | s = s + substr[i] 45 | i = i + 1 46 | return s 47 | 48 | -------------------------------------------------------------------------------- /代码/function_decorator3.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | 4 | def mydecorator(wrapped): 5 | @wraps(wrapped) 6 | def wrapper(*args, **kwargs): 7 | print("I can do anything before calling the target!") 8 | result = wrapped(*args, **kwargs) 9 | print("I can do anything after calling the target!") 10 | return result 11 | return wrapper 12 | 13 | 14 | @mydecorator 15 | def mytarget1(): 16 | print("I am doing nothing.") 17 | return 0 18 | 19 | 20 | @mydecorator 21 | def mytarget2(obj): 22 | print("I am doing the truth value testing.") 23 | return bool(obj) 24 | 25 | 26 | @mydecorator 27 | def mytarget3(x, y): 28 | print("I am an adder.") 29 | return float(x) + float(y) 30 | 31 | 32 | @mydecorator 33 | def mytarget4(*substr): 34 | print("I am an concatenator.") 35 | length = len(substr) 36 | if length == 0: 37 | return '' 38 | elif length == 1: 39 | return substr[0] 40 | else: 41 | i = 0 42 | s = '' 43 | while i < length: 44 | s = s + substr[i] 45 | i = i + 1 46 | return s 47 | 48 | -------------------------------------------------------------------------------- /代码/function_decorator4.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | 4 | #定义一个生成装饰器的函数。 5 | def mydecorator_generator( 6 | before_action=lambda *args, **kwargs: print("I can do anything before calling the target!"), 7 | after_action=lambda *args, **kwargs: print("I can do anything after calling the target!")): 8 | def mydecorator(wrapped): 9 | @wraps(wrapped) 10 | def wrapper(*args, **kwargs): 11 | before_action(*args, **kwargs) 12 | result = wrapped(*args, **kwargs) 13 | after_action(*args, **kwargs) 14 | return result 15 | return wrapper 16 | return mydecorator 17 | 18 | 19 | #定义目标函数1,同时完成装饰。 20 | @mydecorator_generator() 21 | def mytarget1(): 22 | print("I am doing nothing.") 23 | return 0 24 | 25 | 26 | #定义目标函数2,同时完成装饰。 27 | @mydecorator_generator( 28 | lambda *args, **kwargs: None, 29 | lambda *args, **kwargs: None) 30 | def mytarget2(obj): 31 | print("I am doing the truth value testing.") 32 | return bool(obj) 33 | 34 | 35 | #定义目标函数3,同时完成装饰。 36 | @mydecorator_generator( 37 | lambda *args, **kwargs: None, 38 | lambda *args, **kwargs: print("The expression calculated is: " + str(float(args[0])) + "+" + str(float(args[1])))) 39 | def mytarget3(x, y): 40 | print("I am an adder.") 41 | return float(x) + float(y) 42 | 43 | 44 | #定义目标函数4,同时完成装饰。 45 | @mydecorator_generator( 46 | lambda *args, **kwargs: print("Having received " + str(len(args)) + " strings!"), 47 | lambda *args, **kwargs: None) 48 | def mytarget4(*substr): 49 | print("I am an concatenator.") 50 | length = len(substr) 51 | if length == 0: 52 | return '' 53 | elif length == 1: 54 | return substr[0] 55 | else: 56 | i = 0 57 | s = '' 58 | while i < length: 59 | s = s + substr[i] 60 | i = i + 1 61 | return s 62 | 63 | -------------------------------------------------------------------------------- /代码/function_decorator5.py: -------------------------------------------------------------------------------- 1 | #定义被用作装饰器的类。 2 | class mydecorator: 3 | def __init__(self, func): 4 | self.func = func 5 | self.__name__ = func.__name__ 6 | self.__qualname__ = func.__qualname__ 7 | self.__module__ = func.__module__ 8 | self.__doc__ = func.__doc__ 9 | self.__annotations__ = func.__annotations__ 10 | self.__code__ = func.__code__ 11 | self.__defaults__ = func.__defaults__ 12 | self.__kwdefaults__ = func.__kwdefaults__ 13 | self.__globals__ = func.__globals__ 14 | self.__closure__ = func.__closure__ 15 | 16 | def __call__(self, *args, **kwargs): 17 | print("I can do anything before calling the target!") 18 | result = self.func(*args, **kwargs) 19 | print("I can do anything after calling the target!") 20 | return result 21 | 22 | 23 | #定义目标函数1,同时完成装饰。 24 | @mydecorator 25 | def mytarget1(): 26 | print("I am doing nothing.") 27 | return 0 28 | 29 | 30 | #定义目标函数2,同时完成装饰。 31 | @mydecorator 32 | def mytarget2(obj): 33 | print("I am doing the truth value testing.") 34 | return bool(obj) 35 | 36 | 37 | #定义目标函数3,同时完成装饰。 38 | @mydecorator 39 | def mytarget3(x, y): 40 | print("I am an adder.") 41 | return float(x) + float(y) 42 | 43 | 44 | #定义目标函数4,同时完成装饰。 45 | @mydecorator 46 | def mytarget4(*substr): 47 | print("I am an concatenator.") 48 | length = len(substr) 49 | if length == 0: 50 | return '' 51 | elif length == 1: 52 | return substr[0] 53 | else: 54 | i = 0 55 | s = '' 56 | while i < length: 57 | s = s + substr[i] 58 | i = i + 1 59 | return s 60 | 61 | -------------------------------------------------------------------------------- /代码/generator1.py: -------------------------------------------------------------------------------- 1 | #一个简单的生成器函数。 2 | def gen1(): 3 | print("A") 4 | yield 1 5 | print("B") 6 | yield 2 7 | print("C") 8 | yield 3 9 | print("D") 10 | return 0 11 | -------------------------------------------------------------------------------- /代码/generator2.py: -------------------------------------------------------------------------------- 1 | #一个具有参数且使用yield语句的第二种语法的生成器函数。 2 | def gen2(n): 3 | """This generator generates sequence 0, 1, ..., n-1.""" 4 | yield from range(n) 5 | -------------------------------------------------------------------------------- /代码/generator3.py: -------------------------------------------------------------------------------- 1 | class MyIterable: 2 | def __init__(self, seq): 3 | self.data = seq 4 | 5 | def __iter__(self): 6 | length = len(self.data) 7 | i = 0 8 | while i < length: 9 | yield self.data[i] 10 | i += 2 11 | 12 | def __reversed__(self): 13 | i = (len(self.data)-1)//2*2 14 | while i >= 0: 15 | yield self.data[i] 16 | i -= 2 17 | -------------------------------------------------------------------------------- /代码/generator4.py: -------------------------------------------------------------------------------- 1 | #一个会使用yield表达式的求值结果的生成器函数。 2 | def gen3(start, upper_limit): 3 | n = start 4 | while n < upper_limit: 5 | print(n) 6 | n *= (yield n) 7 | -------------------------------------------------------------------------------- /代码/generator5.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | #一个进行了异常处理的生成器函数: 4 | def gen4(): 5 | try: 6 | while True: 7 | n = random.random() 8 | yield n 9 | except RuntimeError: 10 | return 0 11 | -------------------------------------------------------------------------------- /代码/generator6.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def gen5(): 4 | try: 5 | while True: 6 | n = random.random() 7 | yield n 8 | except Exception: 9 | print("Stop generates random numbers.") 10 | return 0 11 | -------------------------------------------------------------------------------- /代码/integer_adder.py: -------------------------------------------------------------------------------- 1 | #该函数只具有仅位置形式参数。 2 | def add1(x, y, /): 3 | return x+y 4 | 5 | 6 | #该函数只具有仅关键字形式参数。 7 | def add2(*, x, y): 8 | return x+y 9 | 10 | 11 | #该函数只具有位置或关键字形式参数。 12 | def add3(x, y): 13 | return x+y 14 | 15 | -------------------------------------------------------------------------------- /代码/interactivehook.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | _old__interactivehook__ = sys.__interactivehook__ 4 | 5 | def echo(): 6 | print("Interactive Mode!") 7 | if _old__interactivehook__: 8 | _old__interactivehook__() 9 | 10 | sys.__interactivehook__ = echo 11 | 12 | del echo 13 | -------------------------------------------------------------------------------- /代码/is_finalizing.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | class Prophet: 4 | def __del__(self): 5 | #该类的实例因解释器关闭而被销毁。 6 | if sys.is_finalizing(): 7 | print("I am dying with the world.") 8 | #该类的实例因其他原因被销毁。 9 | else: 10 | print("I am dying but the world goes on.") 11 | 12 | 13 | -------------------------------------------------------------------------------- /代码/iterate1.py: -------------------------------------------------------------------------------- 1 | #这是一个用while语句迭代序列的例子。 2 | def print_sequence(seq): 3 | #取得序列的长度。 4 | length = len(seq) 5 | #基于索引遍历序列中的元素。 6 | i = 0 7 | while i < length: 8 | print(seq[i]) 9 | i += 1 10 | else: 11 | print("Totally " + str(length) + " elements.") 12 | -------------------------------------------------------------------------------- /代码/iterate2.py: -------------------------------------------------------------------------------- 1 | #这是一个用for语句迭代字典的例子。 2 | def print_dictionary(dict): 3 | #遍历字典中的元素。 4 | for key in dict: 5 | print(str(key) + ": " + str(dict[key])) 6 | else: 7 | print("Traversal finished.") 8 | -------------------------------------------------------------------------------- /代码/iterate3.py: -------------------------------------------------------------------------------- 1 | #这是一个用for语句迭代字典的视图例子。 2 | 3 | 4 | #迭代键构成的视图。 5 | def print_dictionary_keys(dict): 6 | #遍历字典中的键。 7 | for key in dict.keys(): 8 | print(key) 9 | else: 10 | print("Traversal finished.") 11 | 12 | 13 | #迭代值构成的视图。 14 | def print_dictionary_values(dict): 15 | #遍历字典中的值。 16 | for value in dict.values(): 17 | print(value) 18 | else: 19 | print("Traversal finished.") 20 | 21 | 22 | #迭代键值对构成的视图。 23 | def print_dictionary_items(dict): 24 | #遍历字典中的键值对。 25 | for item in dict.items(): 26 | print(item) 27 | else: 28 | print("Traversal finished.") 29 | -------------------------------------------------------------------------------- /代码/iterate4.py: -------------------------------------------------------------------------------- 1 | #这是一个用for语句迭代集合的例子。 2 | def print_set(st): 3 | #遍历集合中的元素。 4 | for ele in st: 5 | print(ele) 6 | -------------------------------------------------------------------------------- /代码/iterate5.py: -------------------------------------------------------------------------------- 1 | #本脚本自定义一个迭代器类。 2 | class MyIterator: 3 | def __init__(self, n): 4 | self.max_n = int(n) 5 | self.n = 0 6 | 7 | #满足迭代器协议对__iter__的要求。 8 | def __iter__(self): 9 | return self 10 | 11 | #满足迭代器协议对__next__的要求。 12 | def __next__(self): 13 | if self.n >= self.max_n: 14 | raise StopIteration() 15 | self.n += 1 16 | return self.n 17 | -------------------------------------------------------------------------------- /代码/iterate6.py: -------------------------------------------------------------------------------- 1 | #本脚本自定义一个可迭代对象类。 它储存一个序列,但被迭代时只取得序列中的偶数项。 2 | class MyIterable: 3 | def __init__(self, seq): 4 | self.data = seq 5 | 6 | #定义专属于该可迭代对象类型的迭代器类。 7 | class EvenIterator(): 8 | def __init__(self, data): 9 | self.data = data 10 | self.length = len(data) 11 | self.index = 0 12 | 13 | def __iter__(self): 14 | return self 15 | 16 | def __next__(self): 17 | if self.index >= self.length: 18 | raise StopIteration() 19 | ele = self.data[self.index] 20 | self.index += 2 21 | return ele 22 | 23 | #返回属于EvenIterator类型的迭代器。 24 | def __iter__(self): 25 | return self.EvenIterator(self.data) 26 | 27 | -------------------------------------------------------------------------------- /代码/iterate7.py: -------------------------------------------------------------------------------- 1 | class MyIterable: 2 | def __init__(self, seq): 3 | self.data = seq 4 | 5 | class EvenIterator(): 6 | def __init__(self, data): 7 | self.data = data 8 | self.length = len(data) 9 | self.index = 0 10 | 11 | def __iter__(self): 12 | return self 13 | 14 | def __next__(self): 15 | if self.index >= self.length: 16 | raise StopIteration() 17 | ele = self.data[self.index] 18 | self.index += 2 19 | return ele 20 | 21 | #方向相反的迭代器的类型。 22 | class ReverseEvenIterator(): 23 | def __init__(self, data): 24 | self.data = data 25 | self.length = len(data) 26 | self.index = (self.length-1)//2*2 27 | 28 | def __iter__(self): 29 | return self 30 | 31 | def __next__(self): 32 | if self.index < 0: 33 | raise StopIteration() 34 | ele = self.data[self.index] 35 | self.index -= 2 36 | return ele 37 | 38 | def __iter__(self): 39 | return self.EvenIterator(self.data) 40 | 41 | #返回方向相反的迭代器。 42 | def __reversed__(self): 43 | return self.ReverseEvenIterator(self.data) 44 | 45 | -------------------------------------------------------------------------------- /代码/lru_cache.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import time 3 | 4 | 5 | #定义一个能缓存128个映射的斐波拉契序列生成函数。 6 | @functools.lru_cache 7 | def fibonacci_lru(n): 8 | if n < 2: 9 | return 1 10 | else: 11 | return fibonacci_lru(n-1) + fibonacci_lru(n-2) 12 | 13 | 14 | #定义一个能缓存10个映射的斐波拉契序列生成函数。 15 | @functools.lru_cache(10) 16 | def fibonacci_10(n): 17 | if n < 2: 18 | return 1 19 | else: 20 | return fibonacci_10(n-1) + fibonacci_10(n-2) 21 | 22 | 23 | #定义一个统计函数执行时间的函数。 24 | def process_time(func, *args, **kwargs): 25 | starttime = time.time() 26 | func(*args, **kwargs) 27 | endtime = time.time() 28 | return endtime - starttime 29 | 30 | -------------------------------------------------------------------------------- /代码/match1.py: -------------------------------------------------------------------------------- 1 | #定义一个模拟菜单的函数。 2 | def menu_simulate(choice): 3 | """This function simulates a menu. 4 | 5 | The virtual menu provides three items: 6 | Setting: chosen by input 1 7 | Help: chosen by input 2 8 | Logout: chosen by input 3 9 | """ 10 | 11 | legal = False 12 | 13 | match choice: 14 | case 1: 15 | legal = True 16 | print("Setting\n") 17 | case 2: 18 | legal = True 19 | print("Help\n") 20 | case 3: 21 | legal = True 22 | print("Logout\n") 23 | 24 | if legal: 25 | return 0 26 | else: 27 | return 1 28 | 29 | 30 | #仅当脚本在顶层环境中运行时才执行。 31 | if __name__ == '__main__': 32 | choice = 0 33 | while choice != 3: 34 | choice = int(input("Menu:\n1 Setting\n2 Help\n3 Logout\n")) 35 | if menu_simulate(choice): 36 | print(str(choice) + ' is an illegal menu item!\n') 37 | 38 | -------------------------------------------------------------------------------- /代码/match10.py: -------------------------------------------------------------------------------- 1 | from Point2D import Point2D 2 | from Point2DFixed import Point2DFixed 3 | 4 | 5 | class Point(Point2DFixed): 6 | __match_args__ = ('x', 'y') 7 | 8 | 9 | def match_point(p): 10 | match p: 11 | case Point2D(x=0, y=0): 12 | print("This Point2D point is the origin.") 13 | case Point2DFixed(x=0): 14 | print("This Point2DFixed point is on the y-axis.") 15 | case Point(_, 0): 16 | print("This Point point is on the x-axis.") 17 | case Point2D(): 18 | print("This Point2D point is not special.") 19 | case Point2DFixed(): 20 | print("This Point2DFixed point is not special.") 21 | case Point(): 22 | print("This Point point is not special.") 23 | -------------------------------------------------------------------------------- /代码/match11.py: -------------------------------------------------------------------------------- 1 | def identify_vowel(letter): 2 | match letter.lower(): 3 | case 'a' | 'e' | 'i' | 'o' | 'u': 4 | print("This letter is a vowel.") 5 | case _: 6 | print("This letter is a consonant.") 7 | -------------------------------------------------------------------------------- /代码/match12.py: -------------------------------------------------------------------------------- 1 | from Point2D import Point2D 2 | from Point2DFixed import Point2DFixed 3 | 4 | def match_point(p): 5 | match p: 6 | case Point2D(x=0, y=0) | Point2DFixed(x=0, y=0) : 7 | print("This point is the origin.") 8 | case Point2D(x=0) | Point2DFixed(x=0) : 9 | print("This point is on the y-axis.") 10 | case Point2D(y=0) | Point2DFixed(y=0): 11 | print("This point is on the x-axis.") 12 | case Point2D() | Point2DFixed(): 13 | print("This Point point is not special.") 14 | -------------------------------------------------------------------------------- /代码/match13.py: -------------------------------------------------------------------------------- 1 | import math 2 | from Point2DFixed import Point2DFixed 3 | 4 | 5 | class Point(Point2DFixed): 6 | __match_args__ = ('x', 'y') 7 | 8 | 9 | def match_point(p): 10 | match p: 11 | case Point(0, 0): 12 | print("This point is the origin.") 13 | case Point(0, y): 14 | print("This point is on the y-axis, distance from origin is " + str(abs(y)) + ".") 15 | case Point(x, 0): 16 | print("This point is on the x-axis, distance from origin is " + str(abs(x)) + ".") 17 | case Point(x, y) if abs(math.sqrt(x**2 + y**2) - 1.0) < 1e-100: 18 | print("This point is on the unit circle.") 19 | case _: 20 | print("This point is not special.") 21 | -------------------------------------------------------------------------------- /代码/match14.py: -------------------------------------------------------------------------------- 1 | def to_arabic(s): 2 | match s.strip().lower(): 3 | case 'zero': 4 | print('zero means 0.') 5 | case 'one': 6 | print('one means 1.') 7 | case 'two': 8 | print('two means 2.') 9 | case 'three': 10 | print('three means 3.') 11 | case 'four': 12 | print('four means 4.') 13 | case 'five': 14 | print('five means 5.') 15 | case 'six': 16 | print('six means 6.') 17 | case 'seven': 18 | print('seven means 7.') 19 | case 'eight': 20 | print('eight means 8.') 21 | case 'nine': 22 | print('nine means 9.') 23 | case s: 24 | print(s + ' is not a number.') 25 | 26 | -------------------------------------------------------------------------------- /代码/match15.py: -------------------------------------------------------------------------------- 1 | def identify_vowel(letter): 2 | match letter.lower(): 3 | case 'a' | 'e' | 'i' | 'o' | 'u' as l: 4 | print(str(l) + " is a vowel.") 5 | case _ as l: 6 | print(str(l) + " is a consonant.") 7 | -------------------------------------------------------------------------------- /代码/match16.py: -------------------------------------------------------------------------------- 1 | from Point2DFixed import Point2DFixed 2 | 3 | 4 | class Point(Point2DFixed): 5 | __match_args__ = ('x', 'y') 6 | 7 | 8 | def identify_shape(points): 9 | match points: 10 | case []: 11 | print("No points.") 12 | case [Point()]: 13 | print("A single point.") 14 | case [Point(), Point()]: 15 | print("A line segment.") 16 | case [Point(), Point(), Point()]: 17 | print("A triangle.") 18 | case [Point(), Point(), *_, Point(), Point()]: 19 | print("A polygon.") 20 | -------------------------------------------------------------------------------- /代码/match17.py: -------------------------------------------------------------------------------- 1 | from Point2DFixed import Point2DFixed 2 | 3 | 4 | class Point(Point2DFixed): 5 | __match_args__ = ('x', 'y') 6 | 7 | 8 | def identify_shape(points): 9 | match points: 10 | case []: 11 | print("No points.") 12 | case [Point() as p1]: 13 | print("A single point at (" 14 | + str(p1.x) + ", " 15 | + str(p1.y) + ").") 16 | case [Point() as p1, Point() as p2]: 17 | print("A line segment from (" 18 | + str(p1.x) + ", " 19 | + str(p1.y) + ") to (" 20 | + str(p2.x) + ", " 21 | + str(p2.y) + ").") 22 | case [Point() as p1, *middle, Point() as p2]: 23 | print("A polygonal line segment from (" 24 | + str(p1.x) + ", " 25 | + str(p1.y) + ") to (" 26 | + str(p2.x) + ", " 27 | + str(p2.y) + ") with " 28 | + str(len(middle)) + " middle points.") 29 | -------------------------------------------------------------------------------- /代码/match18.py: -------------------------------------------------------------------------------- 1 | import math 2 | from Point2DFixed import Point2DFixed 3 | 4 | 5 | class Point(Point2DFixed): 6 | __match_args__ = ('x', 'y') 7 | 8 | 9 | def get_distance(p1=None, p2=None): 10 | match p1, p2: 11 | case (None, None): 12 | print("No points.") 13 | case (Point(x1, y1), None): 14 | print("A single point, the distance from it to origin is " 15 | + str(math.sqrt(x1**2 + y1**2)) + ".") 16 | case (Point(x1, y1), Point(x2, y2)): 17 | print("The distance between the two points is " 18 | + str(math.sqrt((x1 - x2)**2 + (y1 - y2)**2)) + ".") 19 | 20 | -------------------------------------------------------------------------------- /代码/match19.py: -------------------------------------------------------------------------------- 1 | def identify_race(person): 2 | match person: 3 | case { 4 | 'skin': 'white' | 'brown', 5 | 'hair': 'gray' | 'blonde' | 'yellow' | 'red' | 'brown' | 'black', 6 | 'pupil': 'gray' | 'blue' | 'green' | 'red' | 'gold', 7 | **info}: 8 | print(info['name'] + ', ' 9 | + str(info['age']) + ' years old, ' 10 | + 'belongs to the white race.') 11 | case { 12 | 'skin': 'yellow' | 'white', 13 | 'hair': 'black' | 'brown' | 'red', 14 | 'pupil': 'black' | 'brown', 15 | **info}: 16 | print(info['name'] + ', ' 17 | + str(info['age']) + ' years old, ' 18 | + 'belongs to the yellow race.') 19 | case { 20 | 'skin': 'black' | 'brown', 21 | 'hair': 'black', 22 | 'pupil': 'black' | 'brown', 23 | **info}: 24 | print(info['name'] + ', ' 25 | + str(info['age']) + ' years old, ' 26 | + 'belongs to the black race.') 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /代码/match2.py: -------------------------------------------------------------------------------- 1 | def menu_simulate(choice): 2 | """This function simulates a menu. 3 | 4 | The virtual menu provides three items: 5 | Setting: chosen by input 1 6 | Help: chosen by input 2 7 | Logout: chosen by input 3 8 | """ 9 | 10 | match choice: 11 | case 1: 12 | print("Setting\n") 13 | case 2: 14 | print("Help\n") 15 | case 3: 16 | print("Logout\n") 17 | case _: #这是兜底case子句。 18 | print(str(choice) + ' is an illegal menu item!\n') 19 | 20 | 21 | if __name__ == '__main__': 22 | choice = 0 23 | while choice != 3: 24 | choice = int(input("Menu:\n1 Setting\n2 Help\n3 Logout\n")) 25 | menu_simulate(choice) 26 | 27 | -------------------------------------------------------------------------------- /代码/match3.py: -------------------------------------------------------------------------------- 1 | def number_match(a, b): 2 | match a + b: 3 | case 0j: 4 | print("They are opposite numbers.") 5 | case 10.0: 6 | print("They are complementary numbers against 10.") 7 | case 100: 8 | print("They are complementary numbers against 100.") 9 | case _: 10 | print("They have no special relations.") 11 | 12 | -------------------------------------------------------------------------------- /代码/match4.py: -------------------------------------------------------------------------------- 1 | def to_arabic(s): 2 | match s.strip().lower(): 3 | case 'zero': 4 | return 0 5 | case 'one': 6 | return 1 7 | case 'two': 8 | return 2 9 | case 'three': 10 | return 3 11 | case 'four': 12 | return 4 13 | case 'five': 14 | return 5 15 | case 'six': 16 | return 6 17 | case 'seven': 18 | return 7 19 | case 'eight': 20 | return 8 21 | case 'nine': 22 | return 9 23 | case _: 24 | return None 25 | 26 | -------------------------------------------------------------------------------- /代码/match5.py: -------------------------------------------------------------------------------- 1 | def match_specials(v): 2 | match v: 3 | case True: 4 | print("True") 5 | case False: 6 | print("False") 7 | case None: 8 | print("None") 9 | case _: 10 | print("Unkown") 11 | 12 | -------------------------------------------------------------------------------- /代码/match6.py: -------------------------------------------------------------------------------- 1 | class PrimaryColor: 2 | def __init__(self): 3 | self.red = 'red' 4 | self.green = 'green' 5 | self.blue = 'blue' 6 | 7 | 8 | pri_co = PrimaryColor() 9 | 10 | 11 | def pure_color(value): 12 | match value: 13 | case pri_co.red: 14 | print("This color is purely red.") 15 | case pri_co.green: 16 | print("This color is purely green.") 17 | case pri_co.blue: 18 | print("This color is purely blue.") 19 | case _: 20 | print("This color is mixed.") 21 | 22 | -------------------------------------------------------------------------------- /代码/match7.py: -------------------------------------------------------------------------------- 1 | from Point2D import Point2D 2 | from Point2DFixed import Point2DFixed 3 | 4 | def match_point(p): 5 | match p: 6 | case Point2D(): 7 | print("This is a Point2D point.") 8 | case Point2DFixed(): 9 | print("This is a Point2DFixed point.") 10 | -------------------------------------------------------------------------------- /代码/match8.py: -------------------------------------------------------------------------------- 1 | from Point2DFixed import Point2DFixed 2 | 3 | def match_point(p): 4 | match p: 5 | case Point2DFixed(x=0, y=0): 6 | print("This point is the origin.") 7 | case Point2DFixed(x=0): 8 | print("This point is on the y-axis.") 9 | case Point2DFixed(y=0): 10 | print("This point is on the x-axis.") 11 | case Point2DFixed(area=1): 12 | print("This point is on the unit circle.") 13 | case _: 14 | print("This point is not special.") 15 | -------------------------------------------------------------------------------- /代码/match9.py: -------------------------------------------------------------------------------- 1 | from Point2DFixed import Point2DFixed 2 | 3 | 4 | class Point(Point2DFixed): 5 | __match_args__ = ('x', 'y') 6 | 7 | 8 | def match_point(p): 9 | match p: 10 | case Point(0, 0): 11 | print("This point is the origin.") 12 | case Point(0): 13 | print("This point is on the y-axis.") 14 | case Point(_, 0): 15 | print("This point is on the x-axis.") 16 | case Point(_, _, area=1): 17 | print("This point is on the unit circle.") 18 | case _: 19 | print("This point is not special.") 20 | -------------------------------------------------------------------------------- /代码/metaclass1.py: -------------------------------------------------------------------------------- 1 | import types 2 | 3 | 4 | #定义第一个元类。 5 | class meta1(type): 6 | pass 7 | 8 | 9 | #定义第二个元类。 10 | class meta2(type): 11 | pass 12 | 13 | 14 | #定义第三个元类。 15 | class meta3(meta1, meta2): 16 | pass 17 | 18 | 19 | #定义属于meta1的类。 20 | class A(metaclass=meta1): 21 | pass 22 | 23 | 24 | #定义属于meta2的类。 25 | class B(metaclass=meta2): 26 | pass 27 | 28 | 29 | #定义属于meta3的类。 30 | class C(metaclass=meta3): 31 | pass 32 | 33 | 34 | #由于A的元类是meta1,所以最近派生元类是meta1。 35 | print(types.prepare_class("O", (A,), {"metaclass": meta1})) 36 | 37 | #由于A的元类是meta1,meta2和meta1之间没有继承关系,所以发生元类冲突。 38 | try: 39 | print(types.prepare_class("O", (A,), {"metaclass": meta2})) 40 | except TypeError as e: 41 | print(repr(e)) 42 | 43 | #由于A的元类是meta1,而meta3是meta1的子类,所以最近派生元类是meta3。 44 | print(types.prepare_class("O", (A,), {"metaclass": meta3})) 45 | 46 | #由于A的元类是meta1,B的元类是meta2,所以发生元类冲突。 47 | try: 48 | print(types.prepare_class("O", (A, B))) 49 | except TypeError as e: 50 | print(repr(e)) 51 | 52 | #由于A的元类是meta1,C的元类是meta3,而meta3是meta1的子类,所以最近派生元类 53 | # 是meta3。 54 | print(types.prepare_class("O", (A, C))) 55 | 56 | #由于B的元类是meta2,C的元类是meta3,而meta3是meta2的子类,所以最近派生元类 57 | # 是meta3。 58 | print(types.prepare_class("O", (B, C))) 59 | 60 | #由于A的元类是meta1,B的元类是meta2,meta3同时是meta1和meta2的子类,所以最 61 | # 近派生元类是meta3。 62 | print(types.prepare_class("O", (A, B), {"metaclass": meta3})) 63 | 64 | #下面三条语句说明选取最近派生元类的算法是依次两两比较。 65 | 66 | #首先比较A的元类meta1和B的元类meta2,发生元类冲突,不再继续比较。 67 | try: 68 | print(types.prepare_class("O", (A, B, C))) 69 | except TypeError as e: 70 | print(repr(e)) 71 | 72 | #首先比较A的元类meta1和C的元类meta3,选中meta3,然后再比较meta3和B的元类meta2, 73 | # 最后依然选中meta3。 74 | print(types.prepare_class("O", (A, C, B))) 75 | 76 | #首先比较C的元类meta3和A的元类meta1,选中meta3,然后再比较meta3和B的元类meta2, 77 | # 最后依然选中meta3。 78 | print(types.prepare_class("O", (C, A, B))) 79 | 80 | #下面的语句说明通过metaclass关键字指定的元类将与第一个基类比较,且是首先被比较,因 81 | # 此发生元类冲突 82 | try: 83 | print(types.prepare_class("O", (A, C, B), {"metaclass": meta2})) 84 | except TypeError as e: 85 | print(repr(e)) 86 | 87 | -------------------------------------------------------------------------------- /代码/metaclass2.py: -------------------------------------------------------------------------------- 1 | #自定义映射。 2 | class PrefixMapping(dict): 3 | def __init__(self, prefix): 4 | self.prefix = prefix 5 | 6 | def __setitem__(self, key, value): 7 | if key[0] != "_": 8 | dict.__setitem__(self, self.prefix + "_" + key, value) 9 | else: 10 | dict.__setitem__(self, key, value) 11 | 12 | 13 | #定义元类。 14 | class PrefixMeta(type): 15 | @classmethod 16 | def __prepare__(cls, name, bases, **kwds): 17 | return PrefixMapping(name) 18 | 19 | 20 | #定义属于该元类的第一个类。 21 | class A(metaclass=PrefixMeta): 22 | dimension = 2 23 | 24 | def __init__(self, x, y): 25 | self.x = x 26 | self.y = y 27 | 28 | def move(self, dx, dy): 29 | self.x += dx 30 | self.y += dy 31 | 32 | def location(self): 33 | print("(" + str(self.x) + ", " + str(self.y) + ")") 34 | 35 | 36 | #定义属于该元类的第二个类。 37 | class B(metaclass=PrefixMeta): 38 | dimension = 2 39 | 40 | def __init__(self, x, y): 41 | self.x = x 42 | self.y = y 43 | 44 | def move(self, dx, dy): 45 | self.x += dx 46 | self.y += dy 47 | 48 | def location(self): 49 | print("(" + str(self.x) + ", " + str(self.y) + ")") 50 | 51 | -------------------------------------------------------------------------------- /代码/metaclass3.py: -------------------------------------------------------------------------------- 1 | import types 2 | 3 | 4 | #定义元类。 5 | class ConstantMeta(type): 6 | @staticmethod 7 | def __new__(cls, name, bases, dic, **kwds): 8 | new_dic = {} 9 | for k, v in dic.items(): 10 | if isinstance(v, types.FunctionType) or k[0] == '_': 11 | new_dic[k] = v 12 | else: 13 | new_dic[k.upper()] = v 14 | return type.__new__(cls, name, bases, new_dic, **kwds) 15 | 16 | 17 | #定义属于该元类的类。 18 | class Point(metaclass=ConstantMeta): 19 | dimension = 2 20 | 21 | def __init__(self, x, y): 22 | self.x = x 23 | self.y = y 24 | 25 | def move(self, dx, dy): 26 | self.x += dx 27 | self.y += dy 28 | 29 | def location(self): 30 | print("(" + str(self.x) + ", " + str(self.y) + ")") 31 | 32 | -------------------------------------------------------------------------------- /代码/metaclass4.py: -------------------------------------------------------------------------------- 1 | #定义元类。 2 | class Singleton(type): 3 | #为属于该元类的每个类都添加类属性instance。 4 | def __init__(self, *args, **kwargs): 5 | self.instance = None 6 | super().__init__(*args, **kwargs) 7 | 8 | #检查属于该元类的类的instance属性,仅当它不是None时才允许实例化。 9 | def __call__(self, *args, **kwargs): 10 | if self.instance is None: 11 | self.instance = super().__call__(*args, **kwargs) 12 | return self.instance 13 | 14 | 15 | #定义第一个属于Singleton的类。 16 | class A(metaclass=Singleton): 17 | def __init__(self, n, *args): 18 | self.a = n 19 | super().__init__(*args) 20 | 21 | 22 | #定义第二个属于Singleton的类。 23 | class B(metaclass=Singleton): 24 | def __init__(self, n, *args): 25 | self.b = n 26 | super().__init__(*args) 27 | 28 | 29 | #定义第三个属于Singleton的类。 它同时以A和B为直接基类。 30 | class C(A, B): 31 | def __init__(self, n, m, l): 32 | self.c = l 33 | super().__init__(n, m) 34 | 35 | -------------------------------------------------------------------------------- /代码/metaclass5.py: -------------------------------------------------------------------------------- 1 | class A(): 2 | #@classmethod 3 | def __init_subclass__(cls): 4 | raise Exception("class A cannot be used as a base class!") 5 | 6 | class B(A): 7 | pass 8 | -------------------------------------------------------------------------------- /代码/metaclass6.py: -------------------------------------------------------------------------------- 1 | #定义元类。 2 | class FixedAttrMeta(type): 3 | def __init__(self, *args, **kwargs): 4 | #从类定义语句中的attributes关键字获得类属性及其初始值。 将其记录到attrs 5 | # 属性中。 6 | self.attrs = kwargs["attributes"] 7 | #初始化所有类属性。 8 | for k, v in self.attrs.items(): 9 | setattr(self, k, v) 10 | super().__init__(*args, **kwargs) 11 | 12 | #通过反射使得不能添加类属性,也不能修改attrs属性。 13 | def __setattr__(self, name, value): 14 | if name == "attrs": 15 | if not hasattr(self, "attrs"): 16 | super().__setattr__(name, value) 17 | else: 18 | raise Exception("Can not modify attribute attrs!") 19 | elif name in self.attrs: 20 | super().__setattr__(name, value) 21 | else: 22 | raise Exception(f"Can not add attribute {name}!") 23 | 24 | #通过反射使得不能删除类属性。 25 | def __delattr__(self, name): 26 | if name == "attrs" or name in self.attrs: 27 | raise Exception(f"Can not delete attribute {name}!") 28 | else: 29 | return None 30 | 31 | 32 | #定义一个基类,使得__init_subclass__可以接受任何参数。 33 | class FixedAttrBase(): 34 | @classmethod 35 | def __init_subclass__(cls, *args, **kwargs): 36 | object.__init_subclass__() 37 | 38 | 39 | #定义属于FixedAttrMeta的类A,它以FixedAttrBase为基类,除了attr外还具有x和y两个 40 | # 类属性。 41 | class A(FixedAttrBase, metaclass=FixedAttrMeta, attributes={"x": 0, "y":0}): 42 | pass 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /代码/mixed_accumulator.py: -------------------------------------------------------------------------------- 1 | #该函数包含如下参数: 2 | # 位置或关键字参数elements可以接收任意多个操作数,当进行数值累加时它们必须取数值, 3 | # 当进行字符串拼接时它们必须取字符串。 4 | # 仅关键字参数op取如下字符串来指定操作: 5 | # 'sum': 累加。 6 | # 'concat': 拼接。 7 | # 仅关键字参数pre、suf和sep都用于拼接字符串,分别设置前缀、后缀和分隔符。 8 | def mixed_accumulator( 9 | *elements, op='sum', 10 | pre='', suf='', sep=''): 11 | 12 | #确保指定的操作合法。 13 | if op not in ('sum', 'concat'): 14 | return NotImplemented 15 | 16 | #当操作数个数小于2时直接返回结果。 17 | length = len(elements) 18 | if length == 0: 19 | return None 20 | if length == 1: 21 | return elements[0] 22 | 23 | #分别处理累加和拼接。 24 | if op == 'sum': 25 | n = 0 26 | i = 0 27 | while i < length: 28 | n = n + float(elements[i]) 29 | i = i + 1 30 | return n 31 | else: 32 | s = pre 33 | i = 0 34 | while i < length-1: 35 | s = s + str(elements[i]) + sep 36 | i = i + 1 37 | return s + str(elements[length-1]) + suf 38 | 39 | -------------------------------------------------------------------------------- /代码/module1.py: -------------------------------------------------------------------------------- 1 | #定义一个变量。 2 | a = 1 3 | 4 | #定义一个私有变量。 5 | _b = 100 6 | 7 | 8 | #定义一个函数。 9 | def f1(): 10 | return 'f1' 11 | 12 | 13 | #定义一个私有函数。 14 | def _f2(): 15 | return 'f2' 16 | 17 | 18 | #定义一个类。 19 | class C1(): 20 | def echo(self): 21 | return 'C1' 22 | 23 | 24 | #定义一个私有类。 注意这里其实违背了PEP 8的相应推荐。 25 | class _C2(): 26 | def echo(self): 27 | return 'C2' 28 | 29 | 30 | -------------------------------------------------------------------------------- /代码/module2.py: -------------------------------------------------------------------------------- 1 | #定义可导入变量列表。 2 | __all__ = ['a', '_f2', 'C1', '_C2'] 3 | 4 | a = 1 5 | 6 | _b = 100 7 | 8 | 9 | def f1(): 10 | return 'f1' 11 | 12 | 13 | def _f2(): 14 | return 'f2' 15 | 16 | 17 | class C1(): 18 | def echo(self): 19 | return 'C1' 20 | 21 | 22 | class _C2(): 23 | def echo(self): 24 | return 'C2' 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /代码/module3.py: -------------------------------------------------------------------------------- 1 | if __name__ == '__main__': 2 | #仅当作为主模块时才执行的代码。 3 | print("I am executed directly!") 4 | else: 5 | #仅当没有作为主模块时才执行的代码。 6 | print("I am imported.") 7 | 8 | -------------------------------------------------------------------------------- /代码/number_sign_1.py: -------------------------------------------------------------------------------- 1 | s = input("请输入一个整数:") 2 | 3 | n = int(s) 4 | if n < 0: 5 | print("这是一个负数。") 6 | elif n > 0: 7 | print("这是一个正数。") 8 | else: 9 | print("这是零。") 10 | -------------------------------------------------------------------------------- /代码/number_sign_2.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | s = input("请输入一个整数:") 4 | 5 | if re.match(r"^[+\-]?[0-9]+$", s): 6 | n = int(s) 7 | if n < 0: 8 | print("这是一个负数。") 9 | elif n > 0: 10 | print("这是一个正数。") 11 | else: 12 | print("这是零。") 13 | else: 14 | print("您输入的并非整数。") 15 | -------------------------------------------------------------------------------- /代码/number_sign_3.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | s = input("请输入一个整数:") 4 | 5 | if s != "quit": 6 | if re.match(r"^[+\-]?[0-9]+$", s): 7 | n = int(s) 8 | if n < 0: 9 | print("这是一个负数。") 10 | elif n > 0: 11 | print("这是一个正数。") 12 | else: 13 | print("这是零。") 14 | else: 15 | print("您输入的并非整数。") 16 | -------------------------------------------------------------------------------- /代码/number_sign_game_1.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | print("这是一个判断整数符号的小游戏。\n") 4 | 5 | #对变量s赋初始值并保证其逻辑值检测的结果为True。 这样才能避免循环在第一次计算条件 6 | # 表达式时终止。 7 | s = "begin" 8 | 9 | #只要读取到的字符串不是“quit”,就会继续读取。 而当读取到“quit”后,则输出游戏结束 10 | # 的提示。 11 | while s != "quit": 12 | #由于每次循环都读取了不同的字符串,而“quit”会使条件表达式的值的逻辑值检测结果 13 | # 为False,所以该循环不会是死循环。 14 | s = input("请输入一个整数:") 15 | 16 | if re.match(r"^[+\-]?[0-9]+$", s): 17 | n = int(s) 18 | if n < 0: 19 | print("这是一个负数。") 20 | elif n > 0: 21 | print("这是一个正数。") 22 | else: 23 | print("这是零。") 24 | else: 25 | print("您输入的并非整数。") 26 | else: 27 | print("你已经退出了游戏。\n") 28 | -------------------------------------------------------------------------------- /代码/number_sign_game_2.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | print("这是一个判断整数符号的小游戏。\n") 4 | 5 | s = "begin" 6 | 7 | while s != "quit": 8 | s = input("请输入一个整数:") 9 | 10 | #当读取的字符串是“quit”时,继续下一次循环。 11 | if s == "quit": 12 | continue 13 | 14 | if re.match(r"^[+\-]?[0-9]+$", s): 15 | n = int(s) 16 | if n < 0: 17 | print("这是一个负数。") 18 | elif n > 0: 19 | print("这是一个正数。") 20 | else: 21 | print("这是零。") 22 | else: 23 | print("您输入的并非整数。") 24 | else: 25 | print("你已经退出了游戏。\n") 26 | -------------------------------------------------------------------------------- /代码/number_sign_game_3.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | print("这是一个判断整数符号的小游戏。\n") 4 | 5 | while True: 6 | s = input("请输入一个整数:") 7 | 8 | #当读取的字符串是“quit”时,跳出循环。 9 | if s == "quit": 10 | break 11 | 12 | if re.match(r"^[+\-]?[0-9]+$", s): 13 | n = int(s) 14 | if n < 0: 15 | print("这是一个负数。") 16 | elif n > 0: 17 | print("这是一个正数。") 18 | else: 19 | print("这是零。") 20 | else: 21 | print("您输入的并非整数。") 22 | 23 | #本提示仅当循环语句执行完成后才会被输出。 24 | print("你已经退出了游戏。\n") 25 | 26 | -------------------------------------------------------------------------------- /代码/number_sign_game_4.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | #定义函数number_sign_game()。 该函数没有形式参数。 5 | def number_sign_game(): 6 | print("这是一个判断整数符号的小游戏。\n") 7 | 8 | while True: 9 | s = input("请输入一个整数:") 10 | 11 | if s == "quit": 12 | break 13 | 14 | if re.match(r"^[+\-]?[0-9]+$", s): 15 | n = int(s) 16 | if n < 0: 17 | print("这是一个负数。") 18 | elif n > 0: 19 | print("这是一个正数。") 20 | else: 21 | print("这是零。") 22 | else: 23 | print("您输入的并非整数。") 24 | 25 | print("你已经退出了游戏。\n") 26 | 27 | 28 | #调用函数number_sign_game()。 29 | number_sign_game() 30 | 31 | -------------------------------------------------------------------------------- /代码/polymorphism1.py: -------------------------------------------------------------------------------- 1 | import typing 2 | from numbers import Number 3 | from collections.abc import ByteString 4 | 5 | U = typing.Union[int, float, complex] 6 | 7 | #该函数实现了特定多态。 8 | @typing.overload #注册add()的第一个实现。 9 | def add(x: U, y: U) -> U: ... 10 | @typing.overload #注册add()的第二个实现。 11 | def add(x: str, y: str) -> str: ... 12 | @typing.overload #注册add()的第三个实现。 13 | def add(x: ByteString, y: ByteString) -> ByteString: ... 14 | def add(x, y): #定义add()。 15 | #return x + y 16 | #add()的第一个实现。 17 | if isinstance(x, Number) and isinstance(y, Number): 18 | return x + y 19 | #add()的第二个实现。 20 | elif isinstance(x, str) and isinstance(y, str): 21 | return "".join([x, y]) 22 | #add()的第三个实现。 23 | elif isinstance(x, ByteString) and isinstance(y, ByteString): 24 | if isinstance(x, bytes): 25 | return b"".join([x, y]) 26 | else: 27 | return bytearray(b"").join([x, y]) 28 | #当实际参数的类型组合不匹配任何一个实现时,抛出TypeError异常。 29 | else: 30 | raise TypeError 31 | 32 | 33 | if __name__ == "__main__": 34 | print(add(0, 15)) 35 | print(add(8j, 6-9j)) 36 | print(add('a', 'b')) 37 | print(add(b'a', b'b')) 38 | print(add(b'a', bytearray(b'b'))) 39 | print(add(bytearray(b'a'), bytearray(b'b'))) 40 | print(add('a', b'b')) 41 | -------------------------------------------------------------------------------- /代码/polymorphism2.py: -------------------------------------------------------------------------------- 1 | import typing 2 | from collections.abc import Mapping, Sequence 3 | from functools import singledispatch 4 | 5 | U = typing.Union[str, bytes, bytearray] 6 | 7 | 8 | #定义一个泛型函数。 参数obj的类型是泛型,决定分派的结果。 参数maxrow的类型是int, 9 | # 与分派无关。 10 | @singledispatch 11 | def table_gen(obj, maxrow=5): 12 | return [(1, obj)] 13 | 14 | 15 | #以第一种方式将针对Sequence的实现注册给泛型函数。 16 | @table_gen.register 17 | def _(obj: Sequence, maxrow=5): 18 | table = list() 19 | row = 1 20 | for ele in obj: 21 | table.append((row, ele)) 22 | if row == maxrow: 23 | break 24 | row += 1 25 | return table 26 | 27 | 28 | #以第二种方式将针对Mapping的实现注册给泛型函数。 29 | @table_gen.register(Mapping) 30 | def _(obj, maxrow=5): 31 | table = list() 32 | row = 1 33 | for k, v in obj.items(): 34 | table.append((row, k, v)) 35 | if row == maxrow: 36 | break 37 | row += 1 38 | return table 39 | 40 | 41 | #以第三种方式将针对字符串和字节串的实现注册给泛型函数。 42 | table_gen.register(U, lambda obj, maxrow: [(1, obj)]) 43 | 44 | 45 | if __name__ == "__main__": 46 | #调用泛型函数本身。 47 | print(table_gen(0j)) 48 | #调用针对字符串和字节串的实现。 49 | print(table_gen('abc', 5)) 50 | #调用针对Sequence的实现。 51 | print(table_gen([1.6, -8.2, 7.9, 5.4, -0.9], 3)) 52 | #调用针对Mapping的实现。 53 | print(table_gen({'a': b'a', 'b': b'b'})) 54 | #调用泛型函数本身。 55 | print(table_gen({'x', 'y', 'z'})) 56 | -------------------------------------------------------------------------------- /代码/profile1.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | def factorial1(n): 5 | """This function calculates n! using loop.""" 6 | 7 | product = 1 8 | while n > 1: 9 | time.sleep(0.01) 10 | product = product * n 11 | n = n-1 12 | return product 13 | 14 | 15 | def factorial2(n): 16 | """This function calculates n! using recursion.""" 17 | 18 | time.sleep(0.01) 19 | if n > 1: 20 | return n * factorial2(n-1) 21 | else: 22 | return 1 23 | 24 | -------------------------------------------------------------------------------- /代码/profile2.py: -------------------------------------------------------------------------------- 1 | from profile1 import factorial1, factorial2 2 | import cProfile, pstats 3 | 4 | #将Profile对象当成上下文管理器。 5 | with cProfile.Profile(builtins=False) as pro: 6 | #从这里开始收集统计数据。 7 | factorial2(6) 8 | pro.create_stats() 9 | #在这里终止收集统计数据。 10 | factorial1(6) 11 | 12 | #将收集到的统计数据保存到文件。 13 | pro.dump_stats("profile_factorial21") 14 | 15 | #创建一个Stats对象,并显示分析结果。 16 | sta = pstats.Stats("profile_factorial21") 17 | sta.strip_dirs() 18 | sta.print_callers() 19 | 20 | -------------------------------------------------------------------------------- /代码/profile3.py: -------------------------------------------------------------------------------- 1 | from profile1 import factorial2 2 | import cProfile, pstats 3 | 4 | #创建一个空的Profile对象。 5 | pro = cProfile.Profile(builtins=False) 6 | 7 | pro.enable() 8 | #从这里开始收集统计数据。 9 | factorial2(6) 10 | #在这里终止收集统计数据。 11 | pro.disable() 12 | 13 | #创建一个Stats对象,并显示分析结果。 注意这里直接以Profile对象为参数。 14 | sta = pstats.Stats(pro) 15 | sta.strip_dirs() 16 | sta.print_callees() 17 | 18 | -------------------------------------------------------------------------------- /代码/profile4.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import sys 3 | 4 | 5 | #定义通过递归计算斐波那契数列的函数。 6 | def fibonacci(n): 7 | if n < 2: 8 | return 1 9 | else: 10 | return fibonacci(n-1) + fibonacci(n-2) 11 | 12 | 13 | #生成斐波那契数列的前15项,并记录内存使用情况。 14 | seq = [] 15 | n = 0 16 | #清理内部的类型缓存。 17 | sys._clear_type_cache() 18 | #显示初始状态下数列的值、占用内存和已分配块数。 19 | print(f'seq: {seq}') 20 | print(f'seq size: {sys.getsizeof(seq)}') 21 | print(f'block number: {sys.getallocatedblocks()}') 22 | while n < 15: 23 | #向数列中插入一项。 24 | seq.append(fibonacci(n)) 25 | #显示当前状态下数列的值、占用内存和已分配块数。 26 | print(f'seq: {seq}') 27 | print(f'seq size: {sys.getsizeof(seq)}') 28 | print(f'block number: {sys.getallocatedblocks()}') 29 | n += 1 30 | 31 | -------------------------------------------------------------------------------- /代码/quirk_class_definition.py: -------------------------------------------------------------------------------- 1 | #定义类B。 2 | class B: 3 | #类属性b。 4 | b = 0 5 | 6 | 7 | #定义类A。 8 | class A: 9 | #类属性a。 10 | a = 1 11 | 12 | #在初始化时设置__class__特殊属性。 13 | def __init__(self): 14 | self.__class__ = B 15 | -------------------------------------------------------------------------------- /代码/raise1.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | tn = 0 4 | vn = 0 5 | zn = 0 6 | 7 | def f(x, y): 8 | global tn, vn, zn 9 | try: 10 | try: 11 | result = math.nan 12 | result = math.sqrt(x)/y 13 | except TypeError: 14 | tn = tn + 1 15 | raise 16 | except ValueError: 17 | vn = vn + 1 18 | raise 19 | except ZeroDivisionError: 20 | zn = zn + 1 21 | raise 22 | except Exception: 23 | print('tn:' + str(tn) + ', vn:' + str(vn) + ', zn:' + str(zn)) 24 | finally: 25 | return result 26 | -------------------------------------------------------------------------------- /代码/raise2.py: -------------------------------------------------------------------------------- 1 | #自定义异常类,具有下列实例属性: 2 | # low: 合法范围的下限。 3 | # high: 合法范围的上限。 4 | # current: 合法范围之外的当前值。 5 | class RangeError(Exception): 6 | def __init__(self, *args, low=0, high=100, current=-1): 7 | self.low = low 8 | self.high = high 9 | self.current = current 10 | super().__init__(*args) 11 | 12 | #重写魔术属性__str__。 13 | def __str__(self): 14 | extra = ('The legal range is [' 15 | + str(self.low) + ',' + str(self.high) 16 | + '], but the current value is ' 17 | + str(self.current) + '. ') 18 | return extra + super().__str__() 19 | 20 | 21 | #定义代表温度计的类。 22 | class Thermometer(): 23 | def __init__(self, temperature=0): 24 | if temperature < -20 or temperature > 50: 25 | e = RangeError('Out of range!', low=-20, high=50, current=temperature) 26 | e.add_note("Raise during initialization!") 27 | raise e 28 | self.temperature = temperature 29 | 30 | #改变温度计的温度。 31 | def change(self, delta): 32 | temperature = self.temperature + delta 33 | if temperature < -20 or temperature > 50: 34 | e = RangeError('Out of range!', low=-20, high=50, current=temperature) 35 | e.add_note("Raise during changing!") 36 | raise e 37 | self.temperature = temperature 38 | 39 | #以“-”、“0”、“+”和“@”绘制温度计读数。 四个“-”代表零下温度区域,十个“+” 40 | # 代表零上温度区域,“0”代表零度。 “@”代表当前温度,需要替换掉一个“-”、 41 | # “0”或“+”。 42 | def show(self): 43 | scale = '----0++++++++++' 44 | index = self.temperature//5 + 4 45 | marked_scale = scale[0:index] + '@' + scale[index+1:14] 46 | print(marked_scale) 47 | 48 | -------------------------------------------------------------------------------- /代码/raise3.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def f(x, y): 5 | try: 6 | return math.sqrt(x)/y 7 | except TypeError as e: 8 | raise RuntimeError("Please enter two numbers!") from e 9 | except ValueError as e: 10 | raise RuntimeError("x must be non-negative!") from SyntaxError 11 | except ZeroDivisionError as e: 12 | raise RuntimeError("y cannot be 0!") from None 13 | 14 | 15 | def exception_chain(x, y): 16 | try: 17 | f(x, y) 18 | except Exception as e: 19 | print(repr(e.__context__)) 20 | print(repr(e.__cause__)) 21 | print(e.__suppress_context__) 22 | -------------------------------------------------------------------------------- /代码/raise4.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | import types 4 | 5 | def f(x, y): 6 | try: 7 | return math.sqrt(x)/y 8 | except Exception: 9 | t, v, tb = sys.exc_info() 10 | new_tb = types.TracebackType(None, tb.tb_frame, 1, 1) 11 | if t == TypeError: 12 | E = RuntimeError('Please enter two numbers!') 13 | E.with_traceback(new_tb) 14 | raise E from None 15 | elif t == ValueError: 16 | E = RuntimeError('x must be non-negative!') 17 | E.with_traceback(new_tb) 18 | raise E from None 19 | else: 20 | E = RuntimeError('y cannot be 0!') 21 | E.with_traceback(new_tb) 22 | raise E from None 23 | 24 | -------------------------------------------------------------------------------- /代码/scope1.py: -------------------------------------------------------------------------------- 1 | #标识符a是全局变量。 2 | a = -99 3 | 4 | 5 | #标识符outer也是全局变量。 6 | def outer(): 7 | #标识符b是本地变量,其作用域在outer()的函数体内。 8 | b = 35 9 | 10 | #标识符inner也是本地变量,其作用域也在outer()的函数体内。 11 | def inner(): 12 | #标识符c是本地变量,其作用域在inner()的函数体内。 13 | c = 2 14 | #这里使用了标识符abs、a、b和c。 15 | return abs(a + b*c) 16 | 17 | #这里使用了标识符inner。 18 | return inner() 19 | 20 | -------------------------------------------------------------------------------- /代码/scope2.py: -------------------------------------------------------------------------------- 1 | a = -99 2 | 3 | 4 | def outer(): 5 | b = 35 6 | 7 | def inner(): 8 | c = 2 9 | #该绑定屏蔽了外层本地变量b。 10 | b = 10 11 | #该绑定屏蔽了全局变量a。 12 | a = -20 13 | return abs(a + b*c) 14 | 15 | return inner() 16 | 17 | -------------------------------------------------------------------------------- /代码/scope3.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | print('a = ' + str(a)) 3 | 4 | 5 | def f1(): 6 | b = 2 7 | print('b = ' + str(b)) 8 | 9 | def f2(): 10 | c = 3 11 | print('c = ' + str(c)) 12 | 13 | def f3(): 14 | d = 4 15 | #将标识符b和c声明为本地变量中的自由变量。 16 | nonlocal b, c 17 | #将标识符a声明为全局变量。 18 | global a 19 | #直接写入f2()定义的本地变量c。 20 | c = -3 21 | #直接写入f1()定义的本地变量b。 22 | b = -2 23 | #直接写入全局变量a。 24 | a = -1 25 | print('\n') 26 | #列出f3()视角的所有本地变量名称。 27 | print('dir: ' + str(dir())) 28 | #显示f3()视角的所有本地变量状态。 29 | print('locals: ' + str(locals())) 30 | #显示f3()视角的所有全局变量状态。 31 | print('globals: ' + str(globals())) 32 | print('\n') 33 | 34 | f3() 35 | print('c = ' + str(c)) 36 | 37 | f2() 38 | print('b = ' + str(b)) 39 | 40 | f1() 41 | print('a = ' + str(a)) 42 | 43 | 44 | print('\n') 45 | #列出所有全局变量名称。 46 | print('dir: ' + str(dir())) 47 | #显示所有全局变量状态。 48 | print('locals: ' + str(locals())) 49 | #显示所有全局变量状态。 50 | print('globals: ' + str(globals())) 51 | -------------------------------------------------------------------------------- /代码/super.py: -------------------------------------------------------------------------------- 1 | class A: 2 | def who(self): 3 | return 'A' 4 | 5 | class B(A): 6 | def who(self): 7 | return 'B' 8 | 9 | def parent(self): 10 | print ('My parent is ' + super().who()) 11 | 12 | class C(B): 13 | def who(self): 14 | return 'C' 15 | 16 | class D(A): 17 | def who(self): 18 | return 'D' 19 | 20 | class E(C, D): 21 | def who(self): 22 | return 'E' 23 | -------------------------------------------------------------------------------- /代码/typing1.pyi: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | #该全局变量的标注说明它应该引用Tuple[int, str]类型的对象。 4 | a: typing.Tuple[int, str] 5 | 6 | #该赋值语句不会报错,因为符合标注。 7 | a = (0, 'a') 8 | #该赋值语句会报错,因为值的类型为List[object]。 9 | a = [0, 'a'] 10 | #该赋值语句会报错,因为值的类型为Tuple[int]。 11 | a = (0,) 12 | #该赋值语句会报错,因为值的类型为Tuple[int, str, None]。 13 | a = (0, 'a', None) 14 | #该赋值语句会报错,因为值的类型为Tuple[float, bytes]。 15 | a = (0.0, b'a') 16 | 17 | -------------------------------------------------------------------------------- /代码/typing10.pyi: -------------------------------------------------------------------------------- 1 | from typing import Tuple, AnyStr 2 | 3 | 4 | def record(name: AnyStr, data: AnyStr) -> Tuple[AnyStr, AnyStr]: 5 | return (name, data) 6 | 7 | 8 | record("abc", "xyz") 9 | record(b"abc", b"xyz") 10 | record(bytearray(b"abc"), bytearray(b"xyz")) 11 | record("abc", b"xyz") #报错。 12 | record("abc", bytearray(b"xyz")) #报错。 13 | record(b"abc", bytearray(b"xyz")) 14 | 15 | -------------------------------------------------------------------------------- /代码/typing11.py: -------------------------------------------------------------------------------- 1 | from typing import cast, Tuple, TypeVar, TypeVarTuple, Unpack 2 | 3 | T = TypeVar('T', bound=float) 4 | 5 | #定义类型变量元组。 6 | Ts = TypeVarTuple('Ts') 7 | 8 | #定义一个代表元组的类型,该元组至少有一个元素,且第一元素必须是浮点数。 9 | TT = Tuple[T, *Ts] 10 | #兼容Python 3.10的写法。 11 | #TT = Tuple[T, Unpack[Ts]] 12 | 13 | 14 | def sum(data: TT) -> T: 15 | x = cast(T, 0) 16 | for y in data: 17 | x += y 18 | return x 19 | 20 | 21 | if __name__ == "__main__": 22 | print(sum((0, 1.5, True))) 23 | print(sum(tuple())) #报错。 24 | print(sum((1j, 2j))) #报错。 25 | -------------------------------------------------------------------------------- /代码/typing12.pyi: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | 4 | #所有类的基类。 5 | class PointBase(): ... 6 | 7 | 8 | #直接派生自PointBase。 9 | class Point3D(PointBase): ... 10 | 11 | 12 | #直接派生自PointBase。 13 | class PointMove(PointBase): ... 14 | 15 | 16 | #直接派生自PointBase。 17 | class PointShow(PointBase): ... 18 | 19 | 20 | #派生自Point3D。 21 | class Point3DMove(Point3D): ... 22 | 23 | 24 | #T代表Point3D和它的子类。 25 | T = typing.Type[Point3D] 26 | 27 | 28 | def create_point(cls: T): ... 29 | 30 | 31 | if __name__ == "__main__": 32 | create_point(PointBase) #报错。 33 | create_point(Point3D) 34 | create_point(PointMove) #报错。 35 | create_point(PointShow) #报错。 36 | create_point(Point3DMove) 37 | -------------------------------------------------------------------------------- /代码/typing13.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | T = typing.TypeVar("T") 4 | 5 | class A(typing.Generic[T]): 6 | pass 7 | 8 | class B(A[int], list[int]): 9 | pass 10 | 11 | print(f"B.__bases__ == {B.__bases__}") 12 | print(f"B.__mro__ == {B.__mro__}") 13 | 14 | -------------------------------------------------------------------------------- /代码/typing14.pyi: -------------------------------------------------------------------------------- 1 | from typing import Protocol, Callable 2 | from collections.abc import Sequence 3 | 4 | 5 | #回调函数的类型为Callable[[int, int], float]。 6 | def bubble_sort_int(lt: list, compare: Callable[[int, int], float]) -> list: ... 7 | 8 | 9 | #回调函数的类型为Callable[[float, float], float]。 10 | def bubble_sort_float(lt: list, compare: Callable[[float, float], float]) -> list: ... 11 | 12 | 13 | #回调函数的类型为Callable[[str, str], float]。 14 | def bubble_sort_str(lt: list, compare: Callable[[str, str], float]) -> list: ... 15 | 16 | 17 | if __name__ == "__main__": 18 | #该函数的类型为Callable[[int, int], bool]。 19 | def f1(x: int, y: int) -> bool: ... 20 | 21 | 22 | #该函数的类型为Callable[[float, float], int]。 23 | def f2(x: float, y: float) -> int: ... 24 | 25 | 26 | #该函数的类型为Callable[[Sequence, Sequence], float]。 27 | def f3(x: Sequence, y: Sequence) -> float: ... 28 | 29 | 30 | bubble_sort_int(list(), f1) 31 | bubble_sort_int(list(), f2) 32 | bubble_sort_int(list(), f3) #报错。 33 | 34 | bubble_sort_float(list(), f1) #报错。 35 | bubble_sort_float(list(), f2) 36 | bubble_sort_float(list(), f3) #报错。 37 | 38 | bubble_sort_str(list(), f1) #报错 39 | bubble_sort_str(list(), f2) #报错 40 | bubble_sort_str(list(), f3) 41 | -------------------------------------------------------------------------------- /代码/typing15.py: -------------------------------------------------------------------------------- 1 | from typing import Callable, Any 2 | import collections.abc 3 | 4 | 5 | #该函数可以调用任何返回值类型为int的函数,并返回获得的返回值。 在正式执行之前,会先显 6 | # 示即将执行的函数调用。 7 | def verbose(func: Callable[..., int], *args, **kwargs) -> int: 8 | params = "" 9 | for v in args: 10 | params += str(v) + ", " 11 | for k, v in kwargs.items(): 12 | params += str(k) + "=" + str(v)+", " 13 | print(f"executing {func.__name__}({params.strip(', ')})") 14 | return func(*args, **kwargs) 15 | 16 | 17 | if __name__ == "__main__": 18 | #该函数的类型为Callable[[], bool]。 19 | def f1() -> bool: 20 | return True 21 | 22 | 23 | #该函数的类型为Callable[[int, int], int]。 24 | def f2(x: int, y: int) -> int: 25 | return x + y 26 | 27 | 28 | #该函数的类型为Callable[[float, float], float]。 29 | def f3(x: float, y: float) -> float: 30 | return x * y 31 | 32 | 33 | #该函数的类型为Callable[..., str]。 34 | def f4(n: int, s: str, sep: str = "") -> str: 35 | return (n * (s + sep)).rstrip(sep) 36 | 37 | 38 | #该函数的类型为Callable[..., list]。 39 | def f5(*args: Any, reverse: bool = False) -> list: 40 | l = [s for s in args] 41 | if reverse: 42 | l.reverse() 43 | return l 44 | else: 45 | return l 46 | 47 | 48 | print(verbose(f1)) 49 | print("") 50 | print(verbose(f2, 12, 34)) 51 | print("") 52 | print(verbose(f3, 3.6, -1.7)) #报错。 53 | print("") 54 | print(verbose(f4, 3, "abc", sep="@")) #报错。 55 | print("") 56 | print(verbose(f5, False, None, 0, reverse=True)) #报错。 57 | 58 | -------------------------------------------------------------------------------- /代码/typing16.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Callable, ParamSpec, Concatenate 2 | from functools import wraps 3 | 4 | #定义一个参数规格变量。 5 | P = ParamSpec('P') 6 | 7 | 8 | #该装饰器将f(x, y, *, error)装饰为f(pos, neg, zero, y, *, error)。 9 | def decorator(wrapped: Callable[Concatenate[Any, P], int])\ 10 | -> Callable[Concatenate[str, str, str, P], str]: 11 | #这里用到了ParamSpec对象的args属性和kwargs属性。 12 | @wraps(wrapped) 13 | def wrapper(pos: str, neg: str, zero: str, *args: P.args, **kwargs: P.kwargs) -> str: 14 | try: 15 | match wrapped(0, *args, **kwargs): 16 | case 1: 17 | return f"{args[0]} is {pos}." 18 | case -1: 19 | return f"{args[0]} is {neg}." 20 | case _: 21 | return f"{args[0]} is {zero}." 22 | except Exception as e: 23 | if e == kwargs["error"]: 24 | return e.args[0] 25 | else: 26 | raise 27 | return wrapper 28 | 29 | 30 | #定义compare(x, y, *, error),然后将其装饰为compare(pos, neg, zero, y, *, 31 | # error)。 32 | @decorator 33 | def compare(x: Any, y: Any, *, error: Exception = RuntimeError()) -> int: 34 | try: 35 | if y > x: 36 | return 1 37 | elif y < x: 38 | return -1 39 | else: 40 | return 0 41 | except Exception: 42 | raise error 43 | 44 | 45 | if __name__ == "__main__": 46 | print(compare('positive', 'negative', 'zero', 83.2, error=Exception("Not comparable!"))) 47 | print(compare('positive', 'negative', 'zero', -19, error=Exception("Not comparable!"))) 48 | print(compare('positive', 'negative', 'zero', 0, error=Exception("Not comparable!"))) 49 | print(compare('positive', 'negative', 'zero', 0j, error=Exception("Not comparable!"))) 50 | print(compare('+', '-', '0', 18, error=Exception("Not comparable!"))) 51 | print(compare('+', '-', '0', -23.9, error=Exception("Not comparable!"))) 52 | print(compare('+', '-', '0', -0.0, error=Exception("Not comparable!"))) 53 | print(compare('+', '-', '0', 1+9j, error=Exception("Not comparable!"))) 54 | 55 | -------------------------------------------------------------------------------- /代码/typing17.py: -------------------------------------------------------------------------------- 1 | from typing import Union, TypeVar 2 | 3 | T = TypeVar('T', int, str, bytes) 4 | 5 | 6 | #该函数的参数x和y,以及返回值的可能类型都是int、str和bytes,然而三者的类型并不需要是 7 | # 一致的,而可以存在多种组合。 这导致无法用一个类型变量T来作为它们的类型注解,只能使 8 | # 用Union结构。 9 | #def add_concate(x: T, y: T) -> T: 10 | def add_concate(x: Union[int, str, bytes], y: Union[int, str, bytes]) -> Union[int, str, bytes]: 11 | try: 12 | if isinstance(x, int): 13 | if isinstance(y, int): 14 | return x + y 15 | elif isinstance(y, str): 16 | return x * y 17 | elif isinstance(y, bytes) or isinstance(y, bytearray): 18 | return x * y 19 | else: 20 | raise TypeError("y is of bad type!") 21 | elif isinstance(x, str): 22 | if isinstance(y, int): 23 | return x * y 24 | elif isinstance(y, str): 25 | return x + y 26 | elif isinstance(y, bytes) or isinstance(y, bytearray): 27 | raise TypeError("x's type and y's type are inconsistent!") 28 | else: 29 | raise TypeError("y is of bad type!") 30 | elif isinstance(x, bytes) or isinstance(x, bytearray): 31 | if isinstance(y, int): 32 | return x * y 33 | elif isinstance(y, str): 34 | raise TypeError("x's type and y's type are inconsistent!") 35 | elif isinstance(y, bytes) or isinstance(y, bytearray): 36 | return x + y 37 | else: 38 | raise TypeError("y is of bad type!") 39 | else: 40 | raise TypeError("x is of bad type!") 41 | except TypeError as e: 42 | return e.args[0] 43 | 44 | 45 | if __name__ == "__main__": 46 | print(add_concate(2, 3)) 47 | #使用T时报错。 48 | print(add_concate(2, 'abc')) 49 | #使用T时报错。 50 | print(add_concate(2, b'abc')) 51 | #使用T时报错。 52 | print(add_concate(2, bytearray(b'abc'))) 53 | #总是报错。 54 | print(add_concate(2, 3.0)) 55 | print("") 56 | #使用T时报错。 57 | print(add_concate('xyz', 3)) 58 | print(add_concate('xyz', 'abc')) 59 | #使用T时报错。 60 | print(add_concate('xyz', b'abc')) 61 | #使用T时报错。 62 | print(add_concate('xyz', bytearray(b'abc'))) 63 | #总是报错。 64 | print(add_concate('xyz', 3.0)) 65 | 66 | -------------------------------------------------------------------------------- /代码/typing18.pyi: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | NAME: typing.Final = "abc" 4 | 5 | NAME = "def" #报错 6 | 7 | class C(): 8 | NUM: typing.Final[int] = 3.0 #报错 9 | 10 | C.NUM = 3 #报错 11 | -------------------------------------------------------------------------------- /代码/typing19.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | 4 | class A: 5 | #该方法不能被重写。 6 | @typing.final 7 | def a(self): 8 | pass 9 | 10 | def b(self): 11 | pass 12 | 13 | 14 | #该类不能作为其他类的基类。 15 | @typing.final 16 | class B(A): 17 | def a(self) -> int: #报错。 18 | return 0 19 | 20 | def b(self) -> int: 21 | return 0 22 | 23 | 24 | class C(B): #报错。 25 | pass 26 | 27 | -------------------------------------------------------------------------------- /代码/typing2.py: -------------------------------------------------------------------------------- 1 | import typing 2 | import time 3 | 4 | 5 | class Message(typing.TypedDict): 6 | uid: int 7 | time: typing.NotRequired[time.struct_time] 8 | content: str 9 | 10 | 11 | print(f"Message.__total__ == {Message.__total__}") 12 | print(f"Message.__required_keys__ == {Message.__required_keys__}") 13 | print(f"Message.__optional_keys__ == {Message.__optional_keys__}") 14 | 15 | #该赋值语句不会报错。 16 | msg1 = Message(uid=0, content="Hello") 17 | #该赋值语句不会报错。 18 | msg2 = Message(uid=0, time=time.localtime(), content="Hello") 19 | #该赋值语句会因却缺少content属性而报错。 20 | msg3 = Message(uid=0, time=time.localtime()) 21 | #该赋值语句会因却缺少uid属性而报错。 22 | msg4 = Message(content="Hello") 23 | #该赋值语句会因却多出了data属性而报错。 24 | msg5 = Message(uid=0, content="Hello", data=0) 25 | 26 | -------------------------------------------------------------------------------- /代码/typing20.py: -------------------------------------------------------------------------------- 1 | from typing import TypeGuard, Tuple 2 | 3 | 4 | #该TypeGuard结构表明,当is_record()返回True时,通过data参数传入的是一个(str, int) 5 | # 格式的二元组。 6 | def is_record(data: tuple) -> TypeGuard[Tuple[str, int]]: 7 | if len(data) != 2: 8 | return False 9 | if isinstance(data[0], str) and isinstance(data[1], int): 10 | return True 11 | else: 12 | return False 13 | 14 | 15 | print(is_record((0, 1))) #显示False。 16 | print(is_record(('abc', 0, 1))) #显示False。 17 | print(is_record(('abc', 0))) #显示True。 18 | print(is_record((b'abc', 0.0))) #显示False。 19 | 20 | -------------------------------------------------------------------------------- /代码/typing21.py: -------------------------------------------------------------------------------- 1 | from typing import NewType, Tuple 2 | 3 | #创建Tuple[str, int]的一个子类,并将其命名为Record。 4 | Record = NewType('Record', Tuple[str, int]) 5 | 6 | #创建Record的一个子类,并将其命名为Item。 7 | Item = NewType('Item', Record) 8 | 9 | 10 | #该函数需被传入一个Record类型或其子类型的对象。 11 | def show_record(data: Record): 12 | print(data) 13 | 14 | 15 | #t1是Tuple[str, int]类型。 16 | t1 = ('abc', 0) 17 | #t2是Record类型。 18 | t2 = Record(t1) 19 | #t3是Item类型。 20 | t3 = Item(t2) 21 | #显示True,说明t2和t1引用同一个对象。 22 | print(t2 is t1) 23 | #显示True,说明t3和t2引用同一个对象。 24 | print(t3 is t2) 25 | 26 | #传入Tuple[str, int]类型对象,报错。 27 | show_record(t1) 28 | #传入Record类型对象,不报错。 29 | show_record(t2) 30 | #传入Record的子类型对象,不报错。 31 | show_record(t3) 32 | 33 | -------------------------------------------------------------------------------- /代码/typing22.py: -------------------------------------------------------------------------------- 1 | import typing 2 | from numbers import Number 3 | 4 | 5 | def str_or_num(obj: str | int | float): 6 | print(typing.assert_type(obj, str | complex)) #报错。 7 | match obj: 8 | case str(): 9 | #先报告obj的类型,再显示obj。 10 | print(typing.reveal_type(obj)) 11 | case int(): 12 | #先报告obj的类型,再显示obj。 13 | print(typing.reveal_type(obj)) 14 | case _ as unreachable: 15 | try: 16 | typing.assert_never(unreachable) #报错。 17 | except AssertionError: 18 | #先报告obj的类型,再显示obj。 19 | print(typing.reveal_type(obj)) 20 | print("") 21 | 22 | 23 | str_or_num("abc") 24 | str_or_num(b"abc") #报错。 25 | str_or_num(0) 26 | str_or_num(True) 27 | str_or_num(1.3) 28 | str_or_num(None) #报错。 29 | 30 | -------------------------------------------------------------------------------- /代码/typing3.pyi: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | 4 | #定义一个静态鸭子类型Container。 5 | class Container(typing.Protocol): 6 | def __len__(self) -> int: ... 7 | 8 | def __contains__(self, ele) -> bool: ... 9 | 10 | 11 | #Example1实现了Container代表的协议。 12 | class Example1(): 13 | def __len__(self): 14 | return 0 15 | 16 | def __contains__(self, ele): 17 | return False 18 | 19 | 20 | #Example2的__contains__不符合Container的要求,因此没有实现Container代表的协议。 21 | class Example2(): 22 | def __len__(self): 23 | return 0 24 | 25 | def __contains__(self): 26 | return False 27 | 28 | 29 | #声明变量a应该实现Container代表的协议。 30 | a: Container 31 | 32 | #该赋值语句不会报错,因为tuple实现了Container代表的协议。 33 | a = (1, 2, 3) 34 | #该赋值语句不会报错,因为str实现了Container代表的协议。 35 | a = "abc" 36 | #该赋值语句会报错,因为int没有实现Container代表的协议。 37 | a = 0 38 | #该赋值语句不会报错,因为Example1实现了Container代表的协议。 39 | a = Example1() 40 | #该赋值语句会报错,因为Example2没有实现Container代表的协议。 41 | a = Example2() 42 | 43 | -------------------------------------------------------------------------------- /代码/typing4.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | 4 | #定义一个鸭子类型Container。 5 | @typing.runtime_checkable 6 | class Container(typing.Protocol): 7 | def __len__(self) -> int: 8 | pass 9 | 10 | def __contains__(self, ele) -> bool: 11 | pass 12 | 13 | 14 | class Example1(): 15 | def __len__(self): 16 | return 0 17 | 18 | def __contains__(self, ele): 19 | return False 20 | 21 | 22 | class Example2(): 23 | def __len__(self): 24 | return 0 25 | 26 | def __contains__(self): 27 | return False 28 | 29 | -------------------------------------------------------------------------------- /代码/typing5.pyi: -------------------------------------------------------------------------------- 1 | import typing 2 | from collections.abc import Sequence 3 | 4 | #定义一个既没有绑定也没有约束的类型变量。 5 | T1 = typing.TypeVar('T1') 6 | #定义一个有绑定的类型变量。 7 | T2 = typing.TypeVar('T2', bound=Sequence) 8 | #定义一个有约束的类型变量。 9 | T3 = typing.TypeVar('T3', tuple, list) 10 | 11 | 12 | def a(x: T1) -> T1: 13 | return x 14 | 15 | 16 | def b(x: T2) -> T2: 17 | return x 18 | 19 | 20 | def c(x: T3) -> T3: 21 | return x 22 | 23 | 24 | #该函数调用不会报错,因为T1对类型无限制。 25 | a((0, 10)) 26 | #该函数调用不会报错,因为tuple是T2的绑定的子类型。 27 | b((0, 10)) 28 | #该函数调用不会报错,因为tuple在T3的约束中。 29 | c((0, 10)) 30 | #该函数调用不会报错,因为T1对类型无限制。 31 | a([0, 10]) 32 | #该函数调用不会报错,因为list是T2的绑定的子类型。 33 | b([0, 10]) 34 | #该函数调用不会报错,因为list在T3的约束中。 35 | c([0, 10]) 36 | #该函数调用不会报错,因为T1对类型无限制。 37 | a(range(0, 10)) 38 | #该函数调用不会报错,因为range是T2的绑定的子类型。 39 | b(range(0, 10)) 40 | #该函数调用会报错,因为range不在T3的约束中。 41 | c(range(0, 10)) 42 | #该函数调用不会报错,因为T1对类型无限制。 43 | a(0) 44 | #该函数调用会报错,因为int不是T2的绑定的子类型。 45 | b(0) 46 | #该函数调用会报错,因为int不在T3的约束中。 47 | c(0) 48 | 49 | -------------------------------------------------------------------------------- /代码/typing6.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | #代表实数或布尔值的逆变类型变量,它只被用作形式参数的类型注解。 4 | KT = typing.TypeVar('KT', bound=typing.SupportsInt, contravariant=True) 5 | 6 | #代表实数或布尔值的不变类型变量,它同时被用作形式参数和返回值的类型注解。 7 | VT = typing.TypeVar('VT', bound=typing.SupportsInt) 8 | 9 | #代表实数的协变类型变量,它只被用作返回值的类型注解。 10 | ST = typing.TypeVar('ST', int, float, covariant=True) 11 | 12 | 13 | #代表实数或布尔值之间映射的泛型。 14 | class NumMapping(typing.Generic[KT, VT, ST]): 15 | default = False 16 | 17 | def __init__(self, data: dict[KT, VT]): 18 | for k, v in data.items(): 19 | setattr(self, str(k), v) 20 | 21 | def __getitem__(self, k: KT) -> VT: 22 | #这里利用typing.cast()对self.default进行了强制类型转换。 23 | return getattr(self, str(k), typing.cast(VT, self.default)) 24 | 25 | def __setitem__(self, k: KT, v: VT): 26 | setattr(self, str(k), v) 27 | 28 | def __delitem__(self, k: KT): 29 | delattr(self, str(k)) 30 | 31 | def __repr__(self): 32 | s = "" 33 | for k, v in self.__dict__.items(): 34 | if k[0] != "_": 35 | s += k + ": " + str(v) + ", " 36 | return "{" + s.strip(", ") + "}" 37 | 38 | __str__ = __repr__ 39 | 40 | #计算映射中所有值之和。 41 | def sum(self) -> ST: 42 | total = 0 43 | for k, v in self.__dict__.items(): 44 | if k[0] != "_": 45 | total += getattr(self, k) 46 | return total 47 | 48 | 49 | if __name__ == '__main__': 50 | #该赋值语句不会报错,因为int在KT的绑定中,而bool, int和float都在VT的绑定中。 51 | skm1 = NumMapping({1: True, 2: 2, 3: 3.0}) 52 | #该赋值语句会报错,因为str不在KT的绑定中。 53 | skm2 = NumMapping({'1': True, '2': 2, '3': 3.0}) 54 | #该赋值语句会报错,因为complex不在VT的绑定中。 55 | skm3 = NumMapping({1: 1j, 2: 2j, 3: 3j}) 56 | 57 | -------------------------------------------------------------------------------- /代码/typing7.py: -------------------------------------------------------------------------------- 1 | from typing6 import KT, VT, ST, NumMapping 2 | 3 | #创建4个NumMapping的泛型别名。 4 | type1 = NumMapping[int, bool, float] 5 | type2 = NumMapping[int, bool, int] 6 | type3 = NumMapping[float, bool, float] 7 | type4 = NumMapping[float, bool, int] 8 | 9 | #声明四个以不同泛型别名为类型注解的变量。 10 | a: type1 11 | b: type2 12 | c: type3 13 | d: type4 14 | 15 | #验证不同泛型别名允许的子类型范围。 16 | if __name__ == '__main__': 17 | a = type4({1.0: True, 0.0: False}) 18 | a = type3({1.0: True, 0.0: False}) 19 | a = type2({1: True, 0: False}) 20 | a = type1({1: True, 0: False}) 21 | 22 | b = type4({1.0: True, 0.0: False}) 23 | b = type3({1.0: True, 0.0: False}) #报错。 24 | b = type2({1: True, 0: False}) 25 | b = type1({1: True, 0: False}) #报错。 26 | 27 | c = type4({1.0: True, 0.0: False}) 28 | c = type3({1.0: True, 0.0: False}) 29 | c = type2({1: True, 0: False}) #报错。 30 | c = type1({1: True, 0: False}) #报错。 31 | 32 | d = type4({1.0: True, 0.0: False}) 33 | d = type3({1.0: True, 0.0: False}) #报错。 34 | d = type2({1: True, 0: False}) #报错。 35 | d = type1({1: True, 0: False}) #报错。 36 | 37 | -------------------------------------------------------------------------------- /代码/typing8.pyi: -------------------------------------------------------------------------------- 1 | from typing6 import KT, VT, ST, NumMapping, typing 2 | 3 | 4 | #代表实数或布尔值之间映射的鸭子泛型。 5 | class NumMappingProtocol(typing.Protocol[KT, VT, ST]): 6 | def __init__(self, data: dict[KT, VT]): ... 7 | 8 | def __getitem__(self, k: KT) -> VT: ... 9 | 10 | def __setitem__(self, k: KT, v: VT): ... 11 | 12 | def __delitem__(self, k: KT): ... 13 | 14 | def sum(self) -> ST: ... 15 | 16 | 17 | #创建4个NumMapping的泛型别名。 18 | type1 = NumMapping[int, bool, float] 19 | type2 = NumMapping[int, bool, int] 20 | type3 = NumMapping[float, bool, float] 21 | type4 = NumMapping[float, bool, int] 22 | 23 | #创建4个NumMappingProtocol的泛型别名。 24 | protocol1 = NumMappingProtocol[int, bool, float] 25 | protocol2 = NumMappingProtocol[int, bool, int] 26 | protocol3 = NumMappingProtocol[float, bool, float] 27 | protocol4 = NumMappingProtocol[float, bool, int] 28 | 29 | #声明四个以不同泛型别名为类型注解的变量。 30 | a: protocol1 31 | b: protocol2 32 | c: protocol3 33 | d: protocol4 34 | 35 | #验证不同泛型别名允许的子类型范围。 36 | if __name__ == '__main__': 37 | a = type4({1.0: True, 0.0: False}) 38 | a = type3({1.0: True, 0.0: False}) 39 | a = type2({1: True, 0: False}) 40 | a = type1({1: True, 0: False}) 41 | 42 | b = type4({1.0: True, 0.0: False}) 43 | b = type3({1.0: True, 0.0: False}) #报错。 44 | b = type2({1: True, 0: False}) 45 | b = type1({1: True, 0: False}) #报错。 46 | 47 | c = type4({1.0: True, 0.0: False}) 48 | c = type3({1.0: True, 0.0: False}) 49 | c = type2({1: True, 0: False}) #报错。 50 | c = type1({1: True, 0: False}) #报错。 51 | 52 | d = type4({1.0: True, 0.0: False}) 53 | d = type3({1.0: True, 0.0: False}) #报错。 54 | d = type2({1: True, 0: False}) #报错。 55 | d = type1({1: True, 0: False}) #报错。 56 | -------------------------------------------------------------------------------- /代码/typing9.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar, TypedDict, Generic 2 | 3 | T = TypeVar('T') 4 | 5 | 6 | #声明一个属于泛型的TypedDict类型。 7 | class Group(TypedDict, Generic[T]): 8 | leader: T 9 | members: list[T] 10 | 11 | 12 | class Person(): 13 | pass 14 | 15 | 16 | #创建泛型别名。 17 | PersonGroup = Group[Person] 18 | 19 | p1 = Person() 20 | p2 = Person() 21 | 22 | pg1 = PersonGroup(leader=p1, members=[p1, p2]) 23 | pg2 = PersonGroup(leader=p1, members=p2) #报错。 24 | 25 | print(pg1) 26 | print(pg2) 27 | 28 | -------------------------------------------------------------------------------- /代码/warnings1.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | 4 | #调用该函数会发布一个用户自定义警告。 5 | def f(a, b, c): 6 | warnings.warn_explicit( 7 | 'Using this function should be warned!', 8 | UserWarning, 9 | f.__code__.co_filename, 10 | f.__code__.co_firstlineno + 1, 11 | ) 12 | return a*b-c 13 | -------------------------------------------------------------------------------- /代码/warnings2.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | 4 | def f(a, b, c): 5 | warnings.warn('Using this function should be warned!') 6 | return a*b-c 7 | -------------------------------------------------------------------------------- /代码/warnings3.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | 4 | #调用该函数会将一个用户自定义警告写入warning.log文件。 5 | def f(a, b, c): 6 | with open('warning.log', 'a') as fd: 7 | warnings.showwarning( 8 | 'Using this function should be warned!', 9 | UserWarning, 10 | f.__code__.co_filename, 11 | f.__code__.co_firstlineno + 2, 12 | fd 13 | ) 14 | return a*b-c 15 | -------------------------------------------------------------------------------- /代码/warnings4.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | 4 | #调用该函数会将一段用户自定义警告信息写入标准输出。 5 | def f(a, b, c): 6 | msg = warnings.formatwarning( 7 | 'Using this function should be warned!', 8 | UserWarning, 9 | f.__code__.co_filename, 10 | f.__code__.co_firstlineno + 1, 11 | ) 12 | print(msg) 13 | return a*b-c 14 | -------------------------------------------------------------------------------- /代码/warnings5.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | 4 | def __myshowwarning(message, category, filename, lineno, file=None, line=None): 5 | if isinstance(message, Warning): 6 | category = message.__class__ 7 | msg = (str(category) + ": " + str(message) + "\n" 8 | + filename + ", line " + str(lineno) + "\n") 9 | if line is not None: 10 | msg = msg + " " + line + "\n" 11 | print(msg) 12 | 13 | 14 | warnings.showwarning = __myshowwarning 15 | 16 | 17 | def f(a, b, c): 18 | warnings.warn('Using this function should be warned!') 19 | return a*b-c 20 | -------------------------------------------------------------------------------- /代码/weakref1.py: -------------------------------------------------------------------------------- 1 | import typing 2 | import weakref 3 | 4 | 5 | #定义一个函数。 6 | def f1(): 7 | print("I am a function, my name is 'f1'.") 8 | 9 | 10 | #定义一个类,它没有设置__slots__,因此具有__weakref__属性。 11 | class C1(): 12 | def __init__(self, who): 13 | self.who = who 14 | 15 | def m1(self): 16 | print(f"I am '{self.who}'.") 17 | 18 | @classmethod 19 | def m2(cls): 20 | print(f"My class is '{cls.__name__}'.") 21 | 22 | 23 | #定义一个类,它设置了__slots__,但由于以C1为基类,所以也具有__weakref__属性。 24 | class C2(C1): 25 | __slots__ = 'who' 26 | 27 | @staticmethod 28 | def m3(): 29 | print(f"I am 'C2'.") 30 | 31 | 32 | #定义一个类,它不具有__weakref__属性。 33 | class C3(): 34 | __slots__ = 'who' 35 | 36 | -------------------------------------------------------------------------------- /代码/weakref2.py: -------------------------------------------------------------------------------- 1 | import weakref, sys 2 | 3 | #定义第一个回调函数。 4 | def cb1(wr): 5 | print("cb1 is called!") 6 | del wr 7 | raise RuntimeError() 8 | 9 | 10 | #定义第二个回调函数。 11 | def cb2(wr): 12 | print(f"cb2 is called!") 13 | del wr 14 | 15 | 16 | #定义第三个回调函数。 17 | def cb3(wr): 18 | print(f"cb3 is called!") 19 | del wr 20 | 21 | 22 | #定义一个函数来显示一个对象的的引用数、弱引用数和ref对象。 23 | def ref_stat(obj): 24 | print("Reference number: " + str(sys.getrefcount(obj))) 25 | print("WeakRef number: " + str(weakref.getweakrefcount(obj))) 26 | print("WeakRefs: " + repr(weakref.getweakrefs(obj))) 27 | print("") 28 | 29 | 30 | if __name__ == "__main__": 31 | #创建两个集合。 32 | st1 = {'a', 'b', 'c'} 33 | st2 = {'c', 'b', 'a'} 34 | print(f"st1 is {st1}") 35 | print(f"st2 is {st2}") 36 | print("") 37 | 38 | #为st1创建第一个弱引用: 39 | wr1 = weakref.ref(st1, cb1) 40 | print("wr1's callback: " + repr(wr1.__callback__)) 41 | ref_stat(st1) 42 | 43 | #为st1创建第二个弱引用: 44 | wr2 = weakref.ref(st1, cb2) 45 | print("wr2's callback: " + repr(wr2.__callback__)) 46 | ref_stat(st1) 47 | 48 | #为st1创建第三个弱引用: 49 | wr3 = weakref.ref(st1, cb3) 50 | print("wr3's callback: " + repr(wr3.__callback__)) 51 | ref_stat(st1) 52 | 53 | #为st2创建一个弱引用: 54 | wr4 = weakref.ref(st2) 55 | print("wr4's callback: " + repr(wr4.__callback__)) 56 | print("") 57 | 58 | 59 | #验证弱引用之间的比较: 60 | print("wr1 == wr2 == wr3: " + str(wr1 == wr2 == wr3)) 61 | print("wr1 == wr4: " + str(wr1 == wr4)) 62 | print("delete st2!") 63 | del st2 64 | print("wr1 == wr4: " + str(wr1 == wr4)) 65 | print("") 66 | 67 | #删除st1的第二个弱引用,然后删除st1本身。 68 | print("delete wr2!") 69 | del wr2 70 | ref_stat(st1) 71 | print("delete st1!") 72 | del st1 73 | 74 | -------------------------------------------------------------------------------- /代码/weakref3.py: -------------------------------------------------------------------------------- 1 | import weakref 2 | 3 | #定义两个将被弱引用的可哈希对象。 4 | fs1 = frozenset({'a'}) 5 | fs2 = frozenset({'b'}) 6 | 7 | 8 | #该函数显示WeakKeyDictionary对象的键值对。 9 | def show_kv_pairs(wkd): 10 | #调用keyrefs()以获得所有ref对象。 11 | for wr in wkd.keyrefs(): 12 | o = wr() 13 | if o is None: 14 | pass 15 | else: 16 | print(f"{o}: {wkd[o]}") 17 | 18 | 19 | #创建一个空的WeakKeyDictionary对象。 20 | wkd1 = weakref.WeakKeyDictionary() 21 | 22 | #将键值对插入wkd1。 23 | wkd1[fs1] = 1 24 | wkd1[fs2] = 2 25 | 26 | #创建wkd1的拷贝。 27 | wkd2 = weakref.WeakKeyDictionary(wkd1) 28 | 29 | #显示wkd1和wkd2的初始状态。 30 | print("initially") 31 | print("wkd1:") 32 | show_kv_pairs(wkd1) 33 | print("wkd2:") 34 | show_kv_pairs(wkd2) 35 | print("") 36 | 37 | #删除fs1,然后显示wkd1和wkd2现在的状态。 38 | print("delete {fs1}") 39 | del fs1 40 | print("wkd1:") 41 | show_kv_pairs(wkd1) 42 | print("wkd2:") 43 | show_kv_pairs(wkd2) 44 | print("") 45 | 46 | #删除fs2,然后显示wkd1和wkd2现在的状态。 47 | print("delete {fs2}") 48 | del fs2 49 | print("wkd1:") 50 | show_kv_pairs(wkd1) 51 | print("wkd2:") 52 | show_kv_pairs(wkd2) 53 | print("") 54 | 55 | -------------------------------------------------------------------------------- /代码/weakref4.py: -------------------------------------------------------------------------------- 1 | import weakref 2 | 3 | #定义两个将被弱引用的不可哈希对象。 4 | st1 = {'a'} 5 | st2 = {'b'} 6 | 7 | 8 | #该函数显示WeakValueDictionary对象的值。 9 | def show_values(wvd): 10 | #调用valuerefs()以获得所有ref对象。 11 | for wr in wvd.valuerefs(): 12 | o = wr() 13 | if o is None: 14 | pass 15 | else: 16 | print(o) 17 | 18 | 19 | #创建一个空的WeakValueDictionary对象。 20 | wvd1 = weakref.WeakValueDictionary() 21 | 22 | #将键值对插入wvd1。 23 | wvd1[1] = st1 24 | wvd1[2] = st2 25 | 26 | #创建wvd1的拷贝。 27 | wvd2 = weakref.WeakValueDictionary(wvd1) 28 | 29 | #显示wvd1和wvd2的初始状态。 30 | print("initially") 31 | print("wvd1:") 32 | show_values(wvd1) 33 | print("wvd2:") 34 | show_values(wvd2) 35 | print("") 36 | 37 | #删除st1,然后显示wvd1和wvd2现在的状态。 38 | print("delete {st1}") 39 | del st1 40 | print("wvd1:") 41 | show_values(wvd1) 42 | print("wvd2:") 43 | show_values(wvd2) 44 | print("") 45 | 46 | #删除st2,然后显示wvd1和wvd2现在的状态。 47 | print("delete {st2}") 48 | del st2 49 | print("wvd1:") 50 | show_values(wvd1) 51 | print("wvd2:") 52 | show_values(wvd2) 53 | print("") 54 | 55 | -------------------------------------------------------------------------------- /封面和扉页.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/封面和扉页.pdf -------------------------------------------------------------------------------- /第10章. 字符串和二进制序列.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第10章. 字符串和二进制序列.pdf -------------------------------------------------------------------------------- /第11章. 容器.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第11章. 容器.pdf -------------------------------------------------------------------------------- /第12章. 迭代.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第12章. 迭代.pdf -------------------------------------------------------------------------------- /第13章. 模式匹配.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第13章. 模式匹配.pdf -------------------------------------------------------------------------------- /第14章. 异步编程.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第14章. 异步编程.pdf -------------------------------------------------------------------------------- /第15章. 高级话题.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第15章. 高级话题.pdf -------------------------------------------------------------------------------- /第16章. 调试和分析.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第16章. 调试和分析.pdf -------------------------------------------------------------------------------- /第17章. 软件分发.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第17章. 软件分发.pdf -------------------------------------------------------------------------------- /第1章. 你是否需要Python,以及如何掌握Python?.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第1章. 你是否需要Python,以及如何掌握Python?.pdf -------------------------------------------------------------------------------- /第2章. 词法分析.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第2章. 词法分析.pdf -------------------------------------------------------------------------------- /第3章. 数据模型.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第3章. 数据模型.pdf -------------------------------------------------------------------------------- /第4章. 函数.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第4章. 函数.pdf -------------------------------------------------------------------------------- /第5章. 类.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第5章. 类.pdf -------------------------------------------------------------------------------- /第6章. 模块与作用域.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第6章. 模块与作用域.pdf -------------------------------------------------------------------------------- /第7章. Python的运行时服务.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第7章. Python的运行时服务.pdf -------------------------------------------------------------------------------- /第8章. 防御式编程.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第8章. 防御式编程.pdf -------------------------------------------------------------------------------- /第9章. 数字.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/第9章. 数字.pdf -------------------------------------------------------------------------------- /简介和目录.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/简介和目录.pdf -------------------------------------------------------------------------------- /附录 I. 在CentOS 9上安装Python 3.11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/附录 I. 在CentOS 9上安装Python 3.11.pdf -------------------------------------------------------------------------------- /附录 II. 魔术属性.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/附录 II. 魔术属性.pdf -------------------------------------------------------------------------------- /附录 III. 标准解释器类型.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/附录 III. 标准解释器类型.pdf -------------------------------------------------------------------------------- /附录 IV. 内置函数.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/附录 IV. 内置函数.pdf -------------------------------------------------------------------------------- /附录 V. 泛型具象.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/附录 V. 泛型具象.pdf -------------------------------------------------------------------------------- /附录 VI. setuptool.setup()的关键字.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/附录 VI. setuptool.setup()的关键字.pdf -------------------------------------------------------------------------------- /附录 VII. setup.cfg的键.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wwy-gladiolus/Py/c7d13ce74f9476e34879165b00a9176a2794fe24/附录 VII. setup.cfg的键.pdf --------------------------------------------------------------------------------