免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Python标准库实战指南:从内置函数到并发编程的全面解析

Python标准库实战指南:从内置函数到并发编程的全面解析 1. 项目概述为什么Python标准库是每个开发者的必修课如果你刚开始学Python或者已经写了几个月代码可能听过“标准库”这个词但总觉得它庞大、枯燥远不如直接装个requests、pandas来得直接。我以前也这么想直到在一个紧急项目里服务器没有外网无法安装任何第三方包我才真正意识到标准库的价值——它就像瑞士军刀平时觉得功能单一关键时刻却能解决大问题。Python标准库是随Python解释器一同安装的包含了数百个模块覆盖了文件操作、系统交互、数据序列化、网络通信、并发编程等方方面面。它不仅是Python的基石更是体现Python“内置电池”哲学的核心。很多人追求各种炫酷的第三方框架却忽略了脚下这座金山。掌握标准库意味着你能写出更健壮、更可移植、更“Pythonic”的代码而不必为依赖管理头疼。这篇内容就是带你系统性地挖掘这座金山我会结合我踩过的坑和实战经验告诉你哪些模块是高频利器它们怎么用以及为什么这么用。2. 标准库整体架构与核心模块分类Python标准库的模块组织并非随意堆砌而是有清晰的逻辑层次。理解这个架构能帮助你在遇到问题时快速定位到正确的工具而不是盲目搜索。2.1 内置函数与内置类型无需导入的基石这是最底层、最直接可用的部分。print()、len()、type()这些你天天用的就是内置函数。它们之所以“内置”是因为性能最优且是语言语法的一部分。这里有几个容易被忽略但极其强大的enumerate()遍历序列时获取索引和值。新手常用for i in range(len(list)):这既不Pythonic又低效。enumerate()直接返回迭代器内存友好。# 不推荐 my_list [a, b, c] for i in range(len(my_list)): print(i, my_list[i]) # 推荐 for index, value in enumerate(my_list): print(index, value) # 还可以指定起始索引enumerate(my_list, start1)zip()并行迭代多个可迭代对象。处理多组关联数据时非常方便比如合并两个列表成字典。names [Alice, Bob, Charlie] scores [85, 92, 78] # 将两个列表合并成字典 score_dict dict(zip(names, scores)) # {Alice: 85, Bob: 92, Charlie: 78} # 同时遍历 for name, score in zip(names, scores): print(f{name}: {score})注意zip()在Python 3中返回一个迭代器。如果可迭代对象长度不同它会以最短的为准停止。如果需要以最长的为准可以用itertools.zip_longest()。isinstance()vstype()类型检查。type()只返回确切的类型对象而isinstance()会考虑继承关系。在面向对象编程中isinstance()更灵活、更安全。class Animal: pass class Dog(Animal): pass d Dog() print(type(d) Dog) # True print(type(d) Animal) # False print(isinstance(d, Dog)) # True print(isinstance(d, Animal)) # True (因为Dog继承自Animal)内置类型如list、dict、set、tuple的方法也属于这个范畴。例如dict的.get()方法可以避免KeyError.setdefault()可以在键不存在时设置默认值这些都是写健壮代码的细节。2.2 核心服务模块操作系统与系统交互这类模块让你写的Python脚本能真正与计算机环境对话。os与os.path这是与操作系统交互的入口。os用于执行系统命令、管理进程、环境变量os.path专门处理路径字符串它是跨平台的在Windows和Unix上都能正确工作。os.listdir(‘.’)列出当前目录文件。os.path.join(‘folder’, ‘file.txt’)安全地拼接路径自动处理不同操作系统的路径分隔符\或/。永远不要用字符串加法拼接路径os.path.exists(‘/some/path’)检查路径是否存在。os.makedirs(‘a/b/c’, exist_okTrue)递归创建目录exist_okTrue可以避免目录已存在时报错非常实用。sys访问与Python解释器紧密相关的变量和函数。sys.argv获取命令行参数。写脚本工具时必备。sys.pathPython的模块搜索路径列表。当你自定义模块导入失败时检查这里就对了。sys.exit(code)退出程序并返回状态码0表示成功非0通常表示错误。sys.stdin/sys.stdout/sys.stderr标准输入、输出、错误流。可以进行重定向比如将打印内容写入文件。shutil高级文件操作。可以看作是os模块的补充提供了复制、移动、删除整个目录树、压缩归档等更便捷的操作。import shutil # 递归复制整个目录 shutil.copytree(source_dir, dest_dir) # 删除整个目录树危险操作 shutil.rmtree(dir_to_delete)2.3 数据处理与序列化模块程序的核心是处理数据标准库提供了从简单到复杂的多种工具。json现代应用数据交换的绝对主力。用于在Python对象和JSON字符串之间转换。import json data {name: Alice, age: 30, skills: [Python, SQL]} # 序列化Python对象 - JSON字符串 json_str json.dumps(data, indent2) # indent参数让输出更美观 # 反序列化JSON字符串 - Python对象 loaded_data json.loads(json_str) # 与文件交互 with open(data.json, w) as f: json.dump(data, f) # 注意这里是dump不是dumps with open(data.json, r) as f: data_from_file json.load(f)注意json模块默认只能处理Python的基本类型dict, list, str, int, float, bool, None。自定义对象需要额外处理可以通过default和object_hook参数传入自定义的序列化/反序列化函数。csv处理表格数据如Excel导出的CSV文件。虽然pandas更强大但在轻量级场景或依赖受限时csv模块是首选。import csv # 读取CSV with open(data.csv, r, newline, encodingutf-8) as f: # newline防止换行符问题 reader csv.DictReader(f) # 按字典读取键为表头 for row in reader: print(row[Name], row[Age]) # 写入CSV with open(output.csv, w, newline, encodingutf-8) as f: fieldnames [Name, Age] writer csv.DictWriter(f, fieldnamesfieldnames) writer.writeheader() # 写入表头 writer.writerow({Name: Alice, Age: 30})collections内置数据类型的扩展。提供了更多高效、专用的容器数据类型。defaultdict带默认值的字典。访问不存在的键时自动用工厂函数生成默认值避免繁琐的if key not in dict判断。from collections import defaultdict word_count defaultdict(int) # 默认值为0 for word in words: word_count[word] 1 # 即使word第一次出现也不会报错Counter计数器。统计可哈希对象出现次数是词频统计的神器。from collections import Counter words [apple, banana, apple, orange, banana, apple] word_counts Counter(words) print(word_counts) # Counter({apple: 3, banana: 2, orange: 1}) print(word_counts.most_common(2)) # [(apple, 3), (banana, 2)]deque双端队列。在列表开头插入删除元素list.insert(0, item)是O(n)操作而deque在两端都是O(1)适合实现队列、栈或滑动窗口。namedtuple命名元组。给元组的每个位置赋予名字增强代码可读性内存效率比普通类高。from collections import namedtuple Point namedtuple(Point, [x, y]) p Point(10, 20) print(p.x, p.y) # 10 20 比p[0], p[1]清晰多了2.4 日期时间处理datetime模块处理时间几乎是每个程序都会遇到的。datetime模块虽然功能不如pandas.Timestamp或第三方库arrow丰富但胜在无需依赖且足够应对大部分场景。核心类date日期、time时间、datetime日期时间、timedelta时间间隔。获取当前时间datetime.now()。注意它返回的是本地时间的naive对象无时区信息。如果需要带时区用datetime.now(timezone.utc)。时间格式化与解析strftime格式化为字符串和strptime从字符串解析。from datetime import datetime now datetime.now() # 格式化 formatted now.strftime(%Y-%m-%d %H:%M:%S) # 2023-10-27 14:30:00 # 解析 dt datetime.strptime(2023-10-27, %Y-%m-%d)注意strftime和strptime的格式代码如%Y,%m必须严格匹配否则会抛出ValueError。建议将常用的格式字符串定义为常量复用。时间计算使用timedelta进行加减。from datetime import datetime, timedelta today datetime.now().date() yesterday today - timedelta(days1) next_week today timedelta(weeks1)2.5 数学与随机数模块math提供常见的数学函数如三角函数、对数、指数、常数π和e等。这些函数通常比用**运算符或自己实现更精确、更快。random生成伪随机数。注意它不适合用于密码学等安全场景应使用secrets模块。random.random()生成[0.0, 1.0)之间的随机浮点数。random.randint(a, b)生成[a, b]范围内的随机整数。random.choice(seq)从序列中随机选择一个元素。random.shuffle(list)将列表原地打乱顺序。重要为了结果可复现例如在机器学习中固定随机种子可以在程序开始时调用random.seed(42)这样每次运行生成的随机序列都是一样的。3. 文件与IO操作深度解析文件读写是编程中最基础也最易出错的操作之一。标准库提供了不同层次的抽象来应对各种需求。3.1 基础文件操作open函数与上下文管理器open(file, mode, encoding)是入口。最常见的模式是r读文本、w写覆盖、a追加、rb读二进制、wb写二进制。核心要点始终使用上下文管理器with语句这是保证文件被正确关闭的最佳实践即使中间发生异常文件也会被安全关闭避免资源泄漏。# 正确做法 with open(file.txt, r, encodingutf-8) as f: content f.read() # 文件在这里已自动关闭明确指定编码特别是文本文件。在Python 3中不指定encoding参数会使用系统默认编码Windows上是cp1252Linux上是utf-8这会导致跨平台乱码。对于文本文件几乎总是应该使用encodingutf-8。大文件读取策略不要用f.read()一次性读取整个大文件到内存。使用迭代或指定大小读取。# 逐行读取内存友好 with open(large.log, r, encodingutf-8) as f: for line in f: # 文件对象本身是可迭代的 process(line) # 按块读取 chunk_size 1024 * 1024 # 1MB with open(large.bin, rb) as f: while True: chunk f.read(chunk_size) if not chunk: break process(chunk)3.2 路径处理最佳实践pathlibPython 3.4os.path是函数式操作而pathlib提供了面向对象的路径操作方式更现代、更直观。我强烈建议在新项目中使用pathlib。from pathlib import Path # 创建Path对象 current_dir Path(.) # 当前目录 file_path current_dir / data / file.txt # 使用 / 运算符拼接路径非常直观 # 常用操作 if file_path.exists(): print(f文件大小: {file_path.stat().st_size} bytes) print(f父目录: {file_path.parent}) print(f文件名: {file_path.name}) print(f后缀: {file_path.suffix}) # 读写文件 content file_path.read_text(encodingutf-8) # 替代 open().read() file_path.write_text(Hello, pathlib!, encodingutf-8) # 替代 open().write() # 遍历目录 for py_file in current_dir.glob(*.py): # 匹配当前目录所有.py文件 print(py_file) for item in current_dir.rglob(*): # 递归遍历所有文件和目录 print(item)pathlib将许多需要os、os.path、shutil组合完成的操作用更简洁的API统一了起来极大地提升了代码可读性。3.3 序列化与持久化进阶pickle与shelvejson用于和外部系统交换数据而pickle是Python专属的、更强大的序列化模块可以序列化几乎任何Python对象包括自定义类和函数。import pickle data {a: [1, 2, 3], func: lambda x: x*2} # 注意lambda函数也可以被pickle # 序列化到字节流 pickled_bytes pickle.dumps(data) # 反序列化 loaded_data pickle.loads(pickled_bytes) # 序列化到文件 with open(data.pkl, wb) as f: # 必须用二进制模式 pickle.dump(data, f) with open(data.pkl, rb) as f: loaded_from_file pickle.load(f)严重警告pickle不安全永远不要反序列化来自不受信任来源的数据。pickle在反序列化时会执行字节码攻击者可以构造恶意数据在目标机器上执行任意代码。仅在完全可控的环境中使用。shelve模块基于pickle提供了一个简单的键值对数据库接口将Python对象持久化到磁盘文件。import shelve with shelve.open(mydata.db) as db: db[key1] [1, 2, 3] db[key2] {name: Alice} with shelve.open(mydata.db) as db: print(db[key1]) # [1, 2, 3]shelve适合存储配置或小型缓存但它不是真正的数据库不支持并发写也不适合存储大量数据。4. 并发与异步编程基础当任务需要等待I/O如网络请求、磁盘读写时CPU是空闲的。并发编程就是为了充分利用这段时间提高程序效率。标准库提供了多线程、多进程和异步IO三种主要模型。4.1 多线程threading模块线程共享同一进程的内存空间因此通信方便但Python的全局解释器锁GIL限制了同一时刻只有一个线程执行Python字节码所以多线程不适合CPU密集型任务如科学计算但非常适合I/O密集型任务如下载多个文件。基本使用import threading import time def worker(name, delay): print(fWorker {name} started.) time.sleep(delay) print(fWorker {name} finished.) # 创建线程 threads [] for i in range(3): t threading.Thread(targetworker, args(fThread-{i}, i1)) threads.append(t) t.start() # 启动线程 # 等待所有线程完成 for t in threads: t.join() print(All workers done.)线程同步与通信因为共享内存多个线程同时修改一个变量可能导致数据竞争。需要使用锁Lock、信号量Semaphore、队列Queue等同步原语。queue.Queue是线程安全的是线程间通信的首选方式。import threading import queue import time def producer(q): for i in range(5): item fItem-{i} q.put(item) print(fProduced {item}) time.sleep(0.5) q.put(None) # 发送结束信号 def consumer(q): while True: item q.get() if item is None: break print(fConsumed {item}) time.sleep(1) q.task_done() q queue.Queue() prod_thread threading.Thread(targetproducer, args(q,)) cons_thread threading.Thread(targetconsumer, args(q,)) prod_thread.start() cons_thread.start() prod_thread.join() cons_thread.join()4.2 多进程multiprocessing模块进程拥有独立的内存空间不受GIL限制真正利用多核CPU处理计算密集型任务。但进程间通信IPC开销比线程大。基本使用接口与threading非常相似。import multiprocessing import os def cpu_bound_task(n): print(fProcess {os.getpid()} calculating...) return sum(i*i for i in range(n)) if __name__ __main__: # 在Windows上必须加这行 with multiprocessing.Pool(processes4) as pool: # 创建进程池 results pool.map(cpu_bound_task, [1000000, 2000000, 3000000]) print(results)使用Pool进程池可以方便地管理一组工作进程并使用map、apply_async等方法分配任务。进程间通信可以使用multiprocessing.Queue、Pipe管道或共享内存Value,Array。共享内存最快但需要处理同步问题。4.3 异步IOasyncioPython 3.4asyncio是处理高并发I/O的现代方案。它使用单线程通过事件循环Event Loop在多个任务协程间切换当一个任务等待I/O时事件循环就去执行其他任务。这避免了线程/进程切换的开销能轻松支持成千上万的并发连接。核心概念协程Coroutine使用async def定义的函数。它不会立即执行而是返回一个协程对象。await在协程内部用于挂起当前协程等待一个可等待对象Awaitable如另一个协程、Task、Future完成。事件循环Event Loop管理和调度所有协程的核心。基本示例import asyncio import time async def say_after(delay, what): await asyncio.sleep(delay) # 模拟I/O等待不阻塞线程 print(what) async def main(): print(fstarted at {time.strftime(%X)}) # 并发执行两个协程 task1 asyncio.create_task(say_after(1, hello)) task2 asyncio.create_task(say_after(2, world)) await task1 await task2 print(ffinished at {time.strftime(%X)}) # 总共耗时约2秒而不是3秒 asyncio.run(main()) # 运行主协程在这个例子中task1和task2并发执行。当task1在sleep(1)时事件循环会去执行task2所以总时间接近最长任务的耗时2秒而不是串行执行的3秒。与网络请求结合asyncio本身不提供HTTP客户端但可以与aiohttp这样的第三方库完美配合。标准库的asyncio提供了底层的TCP/UDP支持。如何选择I/O密集型且涉及大量网络连接如爬虫、Web服务器首选asyncio。I/O密集型但逻辑简单连接数不多threading足够简单。CPU密集型计算如图像处理、数据科学必须用multiprocessing。混合型既有I/O又有计算可以考虑multiprocessingthreading/asyncio的组合或者使用concurrent.futures模块提供的统一接口。5. 网络编程与互联网数据处理Python在网络领域同样强大标准库提供了从底层Socket到高层协议的支持。5.1 底层网络通信socket模块socket是网络编程的基石。理解它有助于你理解更高层的协议如HTTP是如何工作的。一个简单的TCP服务器/客户端示例# 服务器端 server.py import socket HOST 127.0.0.1 # 本地回环地址 PORT 65432 # 监听端口 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: # AF_INET: IPv4, SOCK_STREAM: TCP s.bind((HOST, PORT)) s.listen() print(fServer listening on {HOST}:{PORT}) conn, addr s.accept() # 等待客户端连接 with conn: print(fConnected by {addr}) while True: data conn.recv(1024) # 接收数据最多1024字节 if not data: break conn.sendall(data) # 将数据原样发回echo server# 客户端 client.py import socket HOST 127.0.0.1 PORT 65432 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) s.sendall(bHello, world!) # 发送字节数据 data s.recv(1024) print(fReceived {data!r})这个例子创建了一个简单的“回声服务器”。实际应用中服务器端通常会使用多线程或selectors模块来处理多个客户端连接。5.2 高层协议客户端urllib与http.client对于日常的HTTP请求我们更常用requests库但标准库的urllib也完全有能力胜任尤其是在依赖受限的环境中。urllib.request用于打开和读取URL。from urllib import request, parse import json # 发起一个简单的GET请求 with request.urlopen(https://httpbin.org/get) as response: data response.read().decode(utf-8) print(json.loads(data)) # 发起一个带数据的POST请求 post_data parse.urlencode({key1: value1, key2: value2}).encode() req request.Request(https://httpbin.org/post, datapost_data) req.add_header(User-Agent, Mozilla/5.0) # 添加请求头 with request.urlopen(req) as response: print(response.status, response.reason) print(response.read().decode())urllib比较底层需要手动处理很多细节如编码、头信息。http.client则提供了更精细的控制但同样繁琐。email与mailbox用于解析和生成电子邮件MIME格式。如果你需要写一个处理邮件的脚本这两个模块是核心。5.3 数据压缩与归档zlib,gzip,tarfile,zipfile处理压缩文件是日常运维和数据处理中的常见任务。gzip处理.gz文件。import gzip # 压缩 with open(large_file.txt, rb) as f_in: with gzip.open(large_file.txt.gz, wb) as f_out: f_out.write(f_in.read()) # 解压 with gzip.open(large_file.txt.gz, rb) as f_in: with open(large_file_decompressed.txt, wb) as f_out: f_out.write(f_in.read())zipfile处理.zip归档文件。import zipfile # 创建zip文件 with zipfile.ZipFile(archive.zip, w) as zf: zf.write(file1.txt) zf.write(file2.txt, arcnamebackup/file2.txt) # 指定归档内路径 # 读取zip文件 with zipfile.ZipFile(archive.zip, r) as zf: zf.extractall(extract_dir) # 解压所有文件 # 查看文件列表 for info in zf.infolist(): print(info.filename, info.file_size)tarfile处理.tar,.tar.gz,.tar.bz2等归档。用法与zipfile类似支持流式读取适合处理大型归档。6. 开发工具与调试支持工欲善其事必先利其器。标准库也包含了许多辅助开发和调试的模块。6.1 日志记录logging模块用print()来调试是初学者的做法生产环境或复杂项目必须使用日志。logging模块提供了灵活的日志记录系统。基本配置与使用import logging # 配置根记录器最简单的方式 logging.basicConfig(levellogging.DEBUG, format%(asctime)s - %(name)s - %(levelname)s - %(message)s, datefmt%Y-%m-%d %H:%M:%S, filenameapp.log, # 输出到文件 filemodea) # 追加模式 # 在代码中使用 logging.debug(这是一条调试信息) # 默认级别为WARNING所以这条不会显示除非level设为DEBUG logging.info(程序正常启动) logging.warning(磁盘空间不足80%) logging.error(连接数据库失败) logging.critical(系统即将崩溃)更佳实践使用命名记录器在大型项目中应为每个模块创建自己的记录器。# 在模块顶部 logger logging.getLogger(__name__) # __name__通常是模块名如myapp.utils # 然后使用logger.info()等这样可以精细控制不同模块的日志级别和输出目的地。日志级别DEBUGINFOWARNINGERRORCRITICAL。设置一个级别后只有该级别及以上的日志才会被处理。6.2 单元测试unittest模块编写测试是保证代码质量的重要手段。unittest是Python自带的测试框架模仿了Java的JUnit。import unittest def add(a, b): return a b class TestMathFunctions(unittest.TestCase): # 测试类必须继承unittest.TestCase def test_add_positive(self): # 测试方法必须以test_开头 self.assertEqual(add(1, 2), 3) self.assertEqual(add(0, 0), 0) def test_add_negative(self): self.assertEqual(add(-1, -1), -2) def test_add_type_error(self): with self.assertRaises(TypeError): # 测试是否抛出特定异常 add(1, 2) if __name__ __main__: unittest.main() # 运行所有测试运行这个脚本unittest会自动发现并运行所有test_开头的方法。它提供了丰富的断言方法assertEqual,assertTrue,assertIn,assertRaises等和测试装置setUp,tearDown来支持复杂的测试场景。6.3 性能分析cProfile与timeit当程序变慢时你需要找到瓶颈。cProfile提供详细的函数调用统计信息包括每个函数被调用的次数、总耗时、平均耗时等。import cProfile import re cProfile.run(re.compile(foo|bar)) # 分析正则表达式编译的性能输出会显示一个表格帮助你定位最耗时的函数。timeit测量小段代码的执行时间精度很高。import timeit # 测量列表推导式和循环创建列表的速度 list_comp_time timeit.timeit([x*x for x in range(100)], number10000) loop_time timeit.timeit( result [] for x in range(100): result.append(x*x) , number10000) print(fList comprehension: {list_comp_time:.4f} sec) print(fFor loop: {loop_time:.4f} sec)timeit会自动禁用垃圾回收并多次运行代码以获得更稳定的结果。6.4 代码质量检查doctest与pydocdoctest让你在文档字符串docstring中嵌入测试用例。它既能作为文档示例又能验证代码是否正确。def factorial(n): 计算阶乘。 factorial(5) 120 factorial(1) 1 factorial(0) 1 if n 1: return 1 return n * factorial(n-1) if __name__ __main__: import doctest doctest.testmod() # 自动运行文档字符串中的测试运行这个脚本如果所有后面的表达式结果与下一行匹配则测试通过否则会报错。这是保证示例代码永远正确的好方法。pydoc可以从命令行生成模块的文档。例如在终端运行python -m pydoc math会显示math模块的文档。python -m pydoc -p 8080会启动一个本地HTTP服务器在浏览器中浏览所有已安装模块的文档。7. 常见问题与排查技巧实录在实际使用标准库的过程中我积累了一些容易踩坑的地方和排查技巧。7.1 编码问题永远的痛问题读写文本文件或处理网络数据时经常遇到UnicodeDecodeError或乱码。根因编码不一致。源文件/数据流的编码与open()或decode()时指定的编码不匹配。排查与解决对于文件尽可能使用encodingutf-8。如果仍报错尝试用二进制模式打开然后用chardet第三方库探测编码。import chardet with open(unknown.txt, rb) as f: raw_data f.read() result chardet.detect(raw_data) encoding result[encoding] text raw_data.decode(encoding)对于网络数据HTTP响应头中的Content-Type字段通常会指定编码如charsetutf-8。优先使用这个信息。如果没有再尝试用chardet探测。黄金法则在程序内部统一使用Unicode字符串Python 3的str类型。只在I/O边界读文件、网络接收、写文件、网络发送进行编码encode和解码decode操作。7.2 路径问题跨平台的坑问题在Windows上写的脚本路径用了反斜杠\到Linux上运行就报错。解决绝对不要手动拼接路径字符串。使用os.path.join()或更现代的pathlib.Path/ 运算符。使用os.path.abspath()和os.path.normpath()来规范化路径。处理用户输入路径时使用os.path.expanduser()来解析~用户主目录。7.3 导入错误ModuleNotFoundError与ImportError问题import my_module时提示找不到模块。排查检查模块文件my_module.py是否在Python的搜索路径sys.path中。可以临时添加路径import sys sys.path.insert(0, /path/to/your/module) import my_module检查是否有循环导入A导入BB又导入A。检查模块名是否与标准库或已安装的第三方库重名。7.4 多线程/多进程中的全局变量与状态问题在多线程中修改一个全局列表结果不符合预期。根因非原子操作如list.append()在多线程环境下可能被打断导致数据错乱。解决对于多线程使用threading.Lock来保护临界区。import threading shared_list [] lock threading.Lock() def safe_append(item): with lock: # 获取锁退出with块时自动释放 shared_list.append(item)对于多进程进程间内存不共享。必须使用multiprocessing模块提供的Queue、Pipe或Manager来通信。Manager可以创建一个服务进程来管理共享对象如list、dict但速度较慢。7.5if __name__ __main__:的作用问题为什么很多脚本最后都有这行解释当一个Python文件被直接运行时其__name__属性被设置为__main__当它被作为模块导入时__name__则是其模块名。这行代码保证了其下的代码块只在文件被直接运行时执行而在被导入时不执行。这对于编写既可独立运行又可被引用的模块至关重要特别是在使用multiprocessing时在Windows系统上必须要有这行否则会引发无限递归创建子进程的错误。7.6 默认参数的可变陷阱问题一个函数的默认参数是空列表[]多次调用后发现列表里积累了之前调用的数据。def append_to(element, target[]): # 危险 target.append(element) return target print(append_to(1)) # [1] print(append_to(2)) # [1, 2] 不是预期的[2]根因默认参数在函数定义时就被求值并绑定而不是每次调用时。这个target参数绑定到了同一个列表对象上。解决使用不可变对象如None作为默认值在函数内部创建可变对象。def append_to(element, targetNone): if target is None: target [] target.append(element) return target掌握Python标准库就像一位工匠熟悉自己工具箱里的每一件工具。它可能没有那些电动工具第三方库功能花哨但绝对可靠、随处可用。在项目初期、在依赖受限的环境、在追求极致轻量的场景下标准库是你的最佳伙伴。花时间深入理解它你的代码会变得更简洁、更高效、也更专业。我个人的习惯是在考虑引入一个新的第三方依赖前总会先问自己一句“标准库里有替代方案吗” 很多时候答案是肯定的。
返回列表