2025.8.20--python基础温习
tracemalloc
模块:跟踪内存分配
import tracemalloc
# Start tracking memory
tracemalloc.start()
# Get memory usage statistics
current, peak = tracemalloc.get_traced_memory()
# Stop tracking memory
tracemalloc.stop()
单个字符串比字符串列表占用内存少,元组占用内存最多
数据存储为字符串列表时,每个字符串都是一个单独的 Python 对象。每个对象都有一些额外的内存要求,其中包括:
- Python 对象标头(通常每个对象 16 - 24 字节)。此标头包含有关对象的信息,例如其类型和引用计数。
- 实际的字符串表示形式本身,它存储字符串的字符。
- 内存对齐填充。这是为确保对象的内存地址正确对齐以实现高效访问而添加的额外空间。
将整个文件内容存储为单个字符串时,只有一个对象,因此只有一组开销。
元组占用最多的原因:1)以结构化格式(元组)存储数据。结构化数据通常需要更多内存,因为它具有定义的组织。2)元组中的每个值都是一个单独的 Python 对象。Python 对象有一些开销,这会导致内存使用量增加。3)一个额外的列表结构来保存所有这些元组。列表还会占用内存来存储其元素。
内存占用:带__slots__
的类 < 元组 < 命名元组 < 常规类 < 字典
具有 __slots__
的类是内存优化类。他们避免使用实例字典,这可以节省内存。
class SlottedRideRecord:__slots__ = ['route', 'date', 'daytype', 'rides']def __init__(self, route, date, daytype, rides):self.route = routeself.date = dateself.daytype = daytypeself.rides = rides
特性 | tuple(元组) | namedtuple(命名元组) |
---|---|---|
可变性 | 不可变 | 不可变(同 tuple) |
访问方式 | 只能通过索引访问 | 可通过索引和属性名访问 |
可读性 | 差(看不出每个值的含义) | 好(字段名清晰表达意义) |
内存开销 | 较小 | 略大(存字段名信息) |
适用场景 | 临时存放、结构简单的数据 | 需要清晰语义的数据结构 |
from collections import Counter
totals = Counter()
totals.most_common([n]) #返回 出现次数最多的元素及其计数,结果是一个 列表,里面是 (元素, 次数) 的元组
from collections import defaultdict
Counter
对象的一大特点是它会自动初始化计数为 0 的新键
defaultdict
类似于常规字典,但它有一个独特的功能。它为尚不存在的键提供默认值。
*
运算符
rows =
[['AA', '100', '32.20'],['IBM', '50', '91.10'],['CAT', '150', '83.44']]for name, *data in rows:print(name,data)AA ['100', '32.20']
IBM ['50', '91.10']
CAT ['150', '83.44']
生成器表达式
生成器表达式根据需要一次生成一个结果。这意味着它不需要一次将所有结果存储在内存中,这可以节省大量内存。
nums = [1, 2, 3, 4, 5]
squares_gen = (x*x for x in nums)
#<generator object <genexpr> at 0x7f9ccbe5ac70>
for n in squares_gen:print(n)
print(next(squares_gen))def squares(nums):for x in nums:yield x*xfor n in squares(nums):print(n)
关于生成器需要注意的一件重要事情是它们只能迭代一次。一旦你遍历了生成器中的所有值,它就会耗尽,你无法再次获取这些值。
装饰器
from functools import total_ordering
@total_ordering
装饰器是 Python 中一个强大的工具。它帮助我们在实现类的比较方法时节省了大量时间和精力。我们只需要定义 __eq__
和另一种比较方法(在本例中为 __lt__
),而不是手动定义所有六种比较方法(__eq__
、__ne__、__lt__
、__le__
、__gt____ge__
)。 然后装饰器会自动为我们生成剩余的四种比较方法。
__index__ = __int__
#它在 Python 中引入,以允许在需要整数索引的情况下使用对象,例如列表索引、按位运算以及各种函数,如 hex()、oct() 和 bin()。
内存使用量
sys.getsizeof()
Python 分配的内存比最初需要的要多,以避免随着列表的增长而频繁重新分配。每次列表超过其当前容量时,Python 都会分配更大的内存块。
sys.intern()
import sys# Without interning
a = 'hello world'
b = 'hello world'
print(f"a is b (without interning): {a is b}") #False# With interning
a = sys.intern(a)
b = sys.intern(b)
print(f"a is b (with interning): {a is b}") #True
类方法:
类方法是绑定到类本身的方法,而不是绑定到实例的方法。
它的特点是:
使用
@classmethod
装饰器来定义。第一个参数约定为
cls
,表示类对象,而不是实例对象。类方法可以访问和修改类属性,但不能直接访问实例属性(因为没有实例
self
)。
私有属性
属性前加上下划线 (_
)。这向其他开发人员发出信号,表明这些属性不是公共 API 的一部分,不应直接从类外部访问。
class Demo:# 类属性category = "Example"count = 0def __init__(self, name):# 实例属性self.name = name# 私有属性self.__secret = "hidden"# 修改类属性Demo.count += 1def show_secret(self):return self.__secret# 创建对象
d1 = Demo("Alice")
d2 = Demo("Bob")# 访问实例属性
print(d1.name) # Alice
print(d2.name) # Bob# 访问类属性
print(Demo.category) # Example
print(d1.count) # 2(共享计数器)
print(d2.count) # 2(共享计数器)# 访问私有属性
# print(d1.__secret) # ❌ 报错,不能直接访问
print(d1.show_secret()) # ✅ hidden
print(d1._Demo__secret) # ✅ hidden(名称改写)
实例属性:每个对象独有,
self.attr
。类属性:所有对象共享,
Class.attr
。私有属性:双下划线隐藏,需通过方法访问。
NotImplementedError
异常用于指示这些方法必须被子类覆盖。如果子类没有覆盖这些方法,而我们尝试使用它们,则会引发错误。
上下文管理器
文件操作:打开文件时,上下文管理器可以确保文件已正确关闭,即使发生错误也是如此。
数据库连接:它可以确保数据库连接在使用完毕后关闭。
线程程序中的锁:上下文管理器可以安全地处理资源的锁定和解锁。
临时更改环境设置:您可以更改代码块的某些设置,然后自动恢复它们。
# 普通写法
f = open("data.txt", "r")
try:content = f.read()
finally:f.close()
# 上下文管理器写法(更简洁)
with open("data.txt", "r") as f:content = f.read()
使用 __enter__
和 __exit__
方法创建上下文管理器
class MyContext:def __enter__(self):print("进入上下文")return "资源"def __exit__(self, exc_type, exc_val, exc_tb):print("退出上下文")if exc_type:print(f"发生异常: {exc_val}")return False # 返回 True 会抑制异常
抽象基类
@abstractmethod
装饰器的方法就像规则一样。从抽象基类继承的任何子类都必须实现这些方法。
from abc import ABC, abstractmethod
#ABC,它是 Python 中所有抽象基类的基类,以及 abstractmethod,它是我们将用来将方法标记为抽象的装饰器。
Mixin 类可以在不更改其原始代码的情况下向类添加额外的功能,主要目的是提供一些可以由另一个类继承的功能。
@property
就是把一个方法包装成 只读属性。
print(s.cost) # ✅ 不需要 s.cost(),直接当属性用
@xxx.setter允许对该属性赋值,并且可以加上检查逻辑。
在 Python 中,对象是基于字典实现的,python对象的3个特征:
1. 每个实例都有自己唯一的属性集。
2. 创建对象后,可以将属性添加到对象中。
3.向一个实例添加属性不会影响其他实例。
类属性由所有实例共享。所有实例都可以访问相同的类属性,而无需拥有自己的副本。
Python 在实例上访问属性时查找属性的顺序:首先检查实例字典,然后检查类字典。
类充当共享数据和行为(方法)的存储库。该类存储其所有实例可以使用的所有通用属性和方法。
如果修改具有相同名称的实例属性,它会隐藏类属性。
继承
合作继承依赖 super()
,让所有类都调用“下一个类”,而不是直接写父类名;在多继承时避免重复调用或遗漏调用。super().method():
“合作继承”
单继承
class A:def spam(self):print('A.spam')class B(A):def spam(self):print('B.spam')super().spam()class C(B):def spam(self):print('C.spam')super().spam()
#类 B 继承自类 A,类 C 继承自类 B。super() 函数用于调用父类的方法。
方法解析顺序
C.__mro__
#(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
多重继承
class Base:def spam(self):print('Base.spam')class X(Base):def spam(self):print('X.spam')super().spam()class Y(Base):def spam(self):print('Y.spam')super().spam()class Z(Base):def spam(self):print('Z.spam')super().spam()
class M(X, Y, Z):passM.__mro__
#(<class '__main__.M'>, <class '__main__.X'>, <class '__main__.Y'>, <class '__main__.Z'>, <class '__main__.Base'>, <class 'object'>)
描述符协议
描述符协议由三种特殊方法组成:__get__()
、__set__()
和 __delete__()
。这些方法分别定义了描述符在访问、分配值或删除属性时的行为方式。
s = Stock('GOOG', 100, 490.10)
s.shares #100q = Stock.__dict__['shares']
q.__get__(s,Stock)
__set_name__
方法增强了描述符以减少冗余
from validate import String, PositiveInteger, PositiveFloatclass Stock:name = String('name')shares = PositiveInteger('shares')price = PositiveFloat('price')##使用__set_name__
class Validator:def __init__(self, name = None):self.name = namedef __set_name__(self, cls, name):# This gets called when the class is defined# It automatically sets the name of the descriptorif self.name is None:self.name = nameclass Stock:name = String() # No need to specify 'name' anymoreshares = PositiveInteger()price = PositiveFloat()
代理
##只读代理
class ReadonlyProxy:def __init__(self, obj):# Store the wrapped object directly in __dict__ to avoid triggering __setattr__self.__dict__['_obj'] = objdef __getattr__(self, name):# Forward attribute access to the wrapped objectreturn getattr(self._obj, name)def __setattr__(self, name, value):# Block all attribute assignmentsraise AttributeError("Cannot modify a read-only object")
__getattr__(self, name):
当 Python 无法以正常方式找到属性时调用此方法。在我们的 ReadonlyProxy
类中,我们使用 getattr()
函数将属性访问请求传递给包装的对象。因此,当尝试访问代理的属性时,它实际上会从包装的对象中获取该属性。
__setattr__(self, name, value)
:当尝试为属性赋值时,将调用此方法
在 __init__
方法中,我们直接修改 self.__dict__
来存储包装的对象。这很重要,因为如果我们使用正常的方式分配对象,它会调用 __setattr__
方法,这会引发错误。
委托delegation
委托涉及包含另一个对象的对象并将特定方法调用转发到该对象。(一个对象将某些功能交由另一个对象来完成,而不是自己直接实现。)
优点:
避免继承层次过深:如果只是为了使用某个类的一些功能,不需要继承整个类。
提高灵活性:委托对象可以随时替换,方便扩展。
单一职责:一个类只关注自己的核心逻辑,其他功能交给委托对象处理。
class Printer:def print_text(self, text):print(f"Printer: {text}")class Manager:def __init__(self):# 委托对象self.printer = Printer()def show_report(self, report):print("Manager: Here is the report header...")# 把打印的事情交给 Printer(委托)self.printer.print_text(report)# 使用
m = Manager()
m.show_report("This is the sales report.")#Manager: Here is the report header...
#Printer: This is the sales report.
委托与继承的区别:
1. 方法重写:在委托中,定义自己的方法并决定是否调用包装对象的方法;在继承中,定义自己的方法并使用 super()
调用父方法。
2. 方法访问:在委托中,未定义的方法通过 __getattr__
方法转发;在继承中,未定义的方法会自动继承。
3.类型关系:使用委派时, isinstance(delegating_spam, Spam)
返回 False
,因为 DelegatingSpam
对象不是 Spam
类的实例;使用继承时, isinstance(inheriting_spam, Spam)
返回 True
,因为 InheritingSpam
类继承自 Spam
类。
4.限制:通过 __getattr__
委派不适用于 __getitem__
、__len__
等特殊方法。这些方法需要在委托类中显式定义。
gzip.open('xxxxxx.csv.gz', 'rt')打开压缩文件
from typing import List, Callable, TypeVar
#Callable 用于表示参数是可以调用的函数T = TypeVar('T')
#让函数或类支持泛型(Generic),即在不确定具体类型时,保持类型一致性。T 表示“某种未知但一致的类型”。
Futures并发编程
import time
import threading
from concurrent.futures import Future, ThreadPoolExecutordef worker(x, y):"""A function that takes time to complete"""print('Starting work...')time.sleep(5) # Simulate a time-consuming taskprint('Work completed')return x + y# Part 1: Normal function call
print("--- Part 1: Normal function call ---")
result = worker(2, 3)
print(f"Result: {result}")# Part 2: Running in a separate thread (problem: no way to get result)
print("\n--- Part 2: Running in a separate thread ---")
t = threading.Thread(target=worker, args=(2, 3))
t.start()
print("Main thread continues while worker runs...")
t.join() # Wait for the thread to complete
print("Worker thread finished, but we don't have its return value!")# Part 3: Using a Future to get the result
print("\n--- Part 3: Using a Future manually ---")def do_work_with_future(x, y, future):"""Wrapper that sets the result in the Future"""result = worker(x, y)future.set_result(result)# Create a Future object
fut = Future()# Start a thread that will set the result in the Future
t = threading.Thread(target=do_work_with_future, args=(2, 3, fut))
t.start()print("Main thread continues...")
print("Waiting for the result...")
# Block until the result is available
result = fut.result() # This will wait until set_result is called
print(f"Got the result: {result}")# Part 4: Using ThreadPoolExecutor (easier way)
print("\n--- Part 4: Using ThreadPoolExecutor ---")
with ThreadPoolExecutor() as executor:# Submit the work to the executorfuture = executor.submit(worker, 2, 3)print("Main thread continues after submitting work...")print("Checking if the future is done:", future.done())# Get the result (will wait if not ready)result = future.result()print("Now the future is done:", future.done())print(f"Final result: {result}")
闭包
闭包提供了一种封装数据的强大方法。封装意味着保持数据的私密性并控制对数据的访问。
nonlocal:用于在 嵌套函数 中声明某个变量不是局部变量,而是外层函数作用域中的变量。
定义:在一个函数内部定义另一个函数,并且 内部函数引用了外部函数的变量,即使外部函数已经执行结束,内部函数依然能“记住”并使用这些变量。
换句话说,闭包就是函数 + 外部作用域的变量的组合。
__set_name__
在描述符中实现 __set_name__
方法时,它可以自动从类定义中获取属性名称。
def __set_name__(self, owner, name):"""owner: 拥有该描述符的类name: 在类中绑定描述符的属性名"""
不用
__set_name__
→ 需要手动传属性名,容易出错。用
__set_name__
→ 属性名自动传入,代码更简洁可靠。
class Positive:def __init__(self, name):self.name = name # 必须手动传入属性名def __get__(self, instance, owner):return instance.__dict__.get(self.name, None)def __set__(self, instance, value):if value <= 0:raise ValueError(f"{self.name} 必须大于 0")instance.__dict__[self.name] = valueclass Person:age = Positive("age") # 必须显式写 "age"height = Positive("height") # 必须显式写 "height"p = Person()
p.age = 18 # ✅ 正常
p.height = -10 # ❌ 抛错 ValueError: height 必须大于 0class Positive:def __set_name__(self, owner, name):self.name = name # 自动获取属性名def __get__(self, instance, owner):return instance.__dict__.get(self.name, None)def __set__(self, instance, value):if value <= 0:raise ValueError(f"{self.name} 必须大于 0")instance.__dict__[self.name] = valueclass Person:age = Positive() # 不需要传 "age"height = Positive() # 不需要传 "height"p = Person()
p.age = 18 # ✅ 正常
p.height = -10 # ❌ 抛错 ValueError: height 必须大于 0
import logging# Set up a logger for this module
logger = logging.getLogger(__name__)logging.basicConfig(level=logging.WARNING)
unittest
import unittest
import stockclass TestStock(unittest.TestCase):def test_create(self):s = stock.Stock('GOOG', 100, 490.1)self.assertEqual(s.name, 'GOOG')self.assertEqual(s.shares, 100)self.assertEqual(s.price, 490.1)def test_create_keyword_args(self):s = stock.Stock(name='GOOG', shares=100, price=490.1)self.assertEqual(s.name, 'GOOG')self.assertEqual(s.shares, 100)self.assertEqual(s.price, 490.1)def test_shares_type(self):s = stock.Stock('GOOG', 100, 490.1)with self.assertRaises(TypeError):s.shares = '50'if __name__ == '__main__':unittest.main()
只想运行特定的测试方法或测试类
python3 -m unittest teststock.TestStock.test_create
unittest
模块自动发现并运行与当前目录中模式 test_*.py
匹配的所有测试文件。它将搜索目录并执行在匹配文件中找到的所有测试用例。
python3 -m unittest discover -s . -p "test_*.py"
#-s 。 指定要启动发现的目录(在本例中为当前目录)。点 (.) 表示当前目录。如果要在其他位置搜索测试,可以将其更改为另一个目录路径。
#-p “test_*.py” 是匹配测试文件的模式。这可确保只有名称以 test_ 开头且扩展名为 .py 的文件才被视为测试文件。
测试驱动开发 (TDD)
函数参数:*args-接受任意数量的位置参数,*
运算符将所有位置参数收集到名为 args
的元组中
**kwargs
参数接受任意数量的关键字参数。**
运算符将所有关键字参数收集到名为 kwargs
的字典中
实现属性限制__setattr__
def __setattr__(self, name, value):"""Restrict attribute setting to only those defined in _fieldsor attributes starting with underscore (private attributes)."""if name.startswith('_'):# Allow setting private attributes (starting with '_')super().__setattr__(name, value)elif name in self._fields:# Allow setting attributes defined in _fieldssuper().__setattr__(name, value)else:# Raise an error for other attributesraise AttributeError(f'No attribute {name}')
方法类型 | 装饰器 | 第一个参数 | 调用方式 | 适用场景 |
---|---|---|---|---|
实例方法 | 无 | self | obj.method() | 需要访问实例属性/方法 |
类方法 | @classmethod | cls | Class.method() | 需要访问类属性/方法 |
静态方法 | @staticmethod | 无 | Class.method() | 不需要访问实例/类,只是逻辑上归类 |
属性的含义:
__name__
:此属性为我们提供了函数的名称。
__module__
:它告诉我们定义函数的模块。当我们在交互式 shell 中运行代码时,模块通常是 __main__
的。
__doc__
:这是函数的文档字符串,它提供了函数功能的简要描述。
__code__
__code__.co_varnames:它是一个元组,包含函数使用的所有局部变量的名称。在我们的 add
函数中,局部变量是 x
和 y
。
co_argcount
:此属性告诉我们函数期望的参数数。我们的 add
函数需要两个参数,因此值为 2。
def add(x, y):'Adds two things'return x + yimport inspect
sig = inspect.signature(add)
print(sig) ##(x, y) 显示函数可以接受哪些参数。
print(sig.parameters)
#OrderedDict([('x', <Parameter "x">), ('y', <Parameter "y">)])
exec
exec()
函数允许执行存储在字符串中的 Python 代码
>>> code = '''
for i in range(n):print(i, end=' ')
'''
>>> n = 10
>>> exec(code)
0 1 2 3 4 5 6 7 8 9
__call__
__call__
让 对象变成可调用对象(callable)
class Greeter:def __init__(self, name):self.name = namedef __call__(self, greeting="Hello"):return f"{greeting}, {self.name}!"g = Greeter("Alice")print(g("Hi")) # 调用 __call__ → "Hi, Alice!"
print(g()) # 默认参数 → "Hello, Alice!"
用类实现装饰器时,通常用 __call__
包装函数
class Logger:def __init__(self, func):self.func = funcdef __call__(self, *args, **kwargs):print(f"Calling {self.func.__name__}")return self.func(*args, **kwargs)@Logger
def add(x, y):return x + yprint(add(2, 3)) # "Calling add" → 5
可配置函数:让一个对象既能保存配置,又能像函数那样执行
class Power:def __init__(self, n):self.n = ndef __call__(self, x):return x ** self.nsquare = Power(2)
cube = Power(3)print(square(4)) # 16
print(cube(2)) # 8
只要一个类实现了下面任意一个方法,就称为 描述符:
__get__(self, instance, owner)
—— 访问属性时触发__set__(self, instance, value)
—— 设置属性时触发__delete__(self, instance)
—— 删除属性时触发
描述符就是把 属性变成方法,从而可以在属性读写时执行额外逻辑。
装饰器
装饰器(Decorator)就是一个 用于包装另一个函数或类的函数/类。主要作用是:在不修改原函数/类代码的前提下,给它添加额外功能。
__init_subclass__
消除了显式应用装饰器的需要
def validate_attributes(cls):"""Class decorator that extracts Validator instancesand builds the _fields list automatically"""validators = []for name, val in vars(cls).items():if isinstance(val, Validator):validators.append(val)# Set _fields based on validator namescls._fields = [val.name for val in validators]# Create initialization methodcls.create_init()return clsclass Structure:_fields = ()_types = ()def __init__(self, *args):if len(args) != len(self._fields):raise TypeError(f'Expected {len(self._fields)} arguments')for name, val in zip(self._fields, args):setattr(self, name, val)def __repr__(self):values = ', '.join(repr(getattr(self, name)) for name in self._fields)return f'{type(self).__name__}({values})'@classmethoddef create_init(cls):'''Create an __init__ method from _fields'''body = 'def __init__(self, %s):\n' % ', '.join(cls._fields)for name in cls._fields:body += f' self.{name} = {name}\n'# Execute the function creation codenamespace = {}exec(body, namespace)setattr(cls, '__init__', namespace['__init__'])@classmethoddef __init_subclass__(cls):validate_attributes(cls)@validate_attributes ##有__init_subclass__,可以把@validate_attributes删除
class Stock(Structure):name = String()shares = PositiveInteger()price = PositiveFloat()@propertydef cost(self):return self.shares * self.pricedef sell(self, nshares):self.shares -= nshares
type()元编程
构造函数创建类
class Validator:def __set_name__(self, owner, name):self.name = namedef __get__(self, instance, owner):if instance is None:return selfreturn instance.__dict__[self.name]def __set__(self, instance, value):self.check(value)instance.__dict__[self.name] = value@classmethoddef check(cls, value):passclass Typed(Validator):expected_type = object # Default, will be overridden in subclasses@classmethoddef check(cls, value):if not isinstance(value, cls.expected_type):raise TypeError(f'Expected {cls.expected_type}')super().check(value)_typed_classes = [('Integer', int),('Float', float),('String', str),('List', list),('Dict', dict),('Bool', bool)
]globals().update((name, type(name, (Typed,), {'expected_type': ty}))for name, ty in _typed_classes)
元类Metaclass
在 Python 中,所有类默认的元类是 type
元类的核心作用是:控制类的创建过程。可以在类生成时,自动修改它的属性、方法,甚至直接替换掉这个类。
元类必须继承自 type
类创建对象,元类创建类
class mytype(type):@staticmethoddef __new__(meta, name, bases, __dict__):print("Creating class :", name)print("Base classes :", bases)print("Attributes :", list(__dict__))return super().__new__(meta, name, bases, __dict__)class myobject(metaclass=mytype):passclass Stock(myobject):def __init__(self, name, shares, price):self.name = nameself.shares = sharesself.price = pricedef cost(self):return self.shares * self.pricedef sell(self, nshares):self.shares -= nshares#meta:这是指元类本身。在我们的例子中,它是 mytype。
#name:这是正在创建的类的名称。
#bases:这是一个元组,包含新类继承的基类。
#__dict__:这是一个包含类属性的字典#Creating class : myobject
#Base classes : ()
#Attributes : ['__module__', '__qualname__']
#Creating class : Stock
#Base classes : (<class '__main__.myobject'>,)
#Attributes : ['__module__', '__qualname__', '__init__', 'cost', 'sell']
from collections import ChainMapclass StructureMeta(type):@classmethod#调用 metaclass 的 __prepare__(clsname, bases),返回一个“命名空间”对象(通常是字典)。def __prepare__(meta, clsname, bases):"""Prepare the namespace for the class being defined"""return ChainMap({}, Validator.validators)from collections import ChainMap
cm = ChainMap({'a': 1}, {'b': 2, 'a': 3})
print(cm['a']) # 1(查找时优先第一个字典)
print(cm['b']) # 2
from collections import deque# Task queue
tasks = deque()# Simple task scheduler
def run():while tasks:task = tasks.popleft() # Get the next tasktry:task.send(None) # Resume the tasktasks.append(task) # Put it back in the queueexcept StopIteration:print('Task done') # Task is complete# Example task 1: Countdown
def countdown(n):while n > 0:print('T-minus', n)yield # Pause executionn -= 1# Example task 2: Count up
def countup(n):x = 0while x < n:print('Up we go', x)yield # Pause executionx += 1if __name__ == '__main__':# Add tasks to the queuetasks.append(countdown(10)) # Count down from 10tasks.append(countdown(5)) # Count down from 5tasks.append(countup(20)) # Count up to 20# Run all tasksrun()
套接字(Socket)是计算机网络编程中的一种 通信机制,它为应用层与传输层之间提供了一个编程接口。简单来说,套接字就是网络通信的“端点”,两台计算机之间要进行数据传输,就需要在两端各自创建一个套接字,通过它们实现数据的收发。
套接字的基本编程模型
以 TCP 为例,服务器和客户端的典型流程:
服务器端:
socket()
—— 创建套接字bind()
—— 绑定 IP 和端口listen()
—— 监听端口accept()
—— 等待客户端连接recv()/send()
—— 接收和发送数据close()
—— 关闭套接字
客户端:
socket()
—— 创建套接字connect()
—— 连接服务器send()/recv()
—— 发送和接收数据close()
—— 关闭套接字
throw():在 Python 里主要是 生成器对象(generator object)的方法,它的作用是 向生成器内部抛出异常,从而控制生成器的执行流程。
generator.throw(type, value=None, traceback=None)
#type:要抛出的异常类型(必须是 Exception 的子类,或者异常实例)。
#value:异常的参数(如果 type 是异常类,这里就是实例化时的参数)。
#traceback:异常追踪信息(一般不用,调试时才会用)。
throw()
会在 生成器当前暂停的位置(即 yield
表达式处)抛出指定的异常。
def gen():try:yield "ready"except ValueError as e:print("caught inside:", e)yield "recovered"yield "done"g = gen()
print(next(g)) # → "ready"print(g.throw(ValueError, "bad value")) # 向生成器里抛异常,被捕获 → "recovered"print(next(g)) # → "done"
yield from
用于在一个生成器(generator)中委托子生成器,即可以把一个生成器的生成过程交给另一个生成器处理,同时简化代码和增强可读性。
yield from <iterable>
#等价于
for item in iterable:yield item
使用 types
模块中的 @coroutine
装饰器。这个装饰器有助于将基于生成器的函数转换为可以与 async
/await
一起使用的形式。
强制重新加载模块,使用 importlib.reload()
函数。
##验证simplemod模块是否已加载
'simplemod' in sys.modules##删除模块
del sys.modules['simplemod']
从模块导入变量时,我们实际上是在本地命名空间中创建对同一对象的新引用。
from simplemod import foo,x
>>> x = 13 # Change the local variable x
>>> x
13
>>> foo()
x is 42 # The function still uses the module's x, not your local x
动态导入和类注册
动态导入指的是在运行时(runtime)根据条件去加载模块,而不是在代码开头固定写死 import xxx
。
#内置 __import__
__import__(f'{__package__}.formats.{name}')
#importlib 模块
import importlibmodule_name = "math"
math_module = importlib.import_module(module_name)
print(math_module.sqrt(25)) # 5.0
类注册就是把某些类放到一个“注册表”中,方便后续按名字来创建实例,而不是硬编码类。
这是一种常用的工厂模式实现手段。
#手动注册
REGISTRY = {}def register_class(name, cls):REGISTRY[name] = clsclass A:passclass B:passregister_class("A", A)
register_class("B", B)# 使用注册表创建对象
obj = REGISTRY["A"]()
print(obj) # <__main__.A object at ...>#使用装饰器自动注册
REGISTRY = {}def register(name):def wrapper(cls):REGISTRY[name] = clsreturn clsreturn wrapper@register("Foo")
class Foo:pass@register("Bar")
class Bar:passprint(REGISTRY) # {'Foo': <class '__main__.Foo'>, 'Bar': <class '__main__.Bar'>}#基于基类的自动注册
class Base:registry = {}def __init_subclass__(cls, **kwargs):super().__init_subclass__(**kwargs)Base.registry[cls.__name__] = clsclass Cat(Base):passclass Dog(Base):passprint(Base.registry)
# {'Cat': <class '__main__.Cat'>, 'Dog': <class '__main__.Dog'>}