
1. 从“Hello, World!”到模块化编程为什么我们需要import如果你刚开始学习Python可能写过类似print(Hello, World!)这样的代码。这很直接所有功能都写在一个文件里。但随着你想做的事情越来越多比如读取文件、获取当前时间、生成随机数你会发现代码越来越长越来越难以管理。这时Python的模块系统就登场了而import就是打开这个宝库的钥匙。简单来说一个.py文件就是一个模块。模块让你能把相关的代码变量、函数、类组织在一起形成一个独立的单元。import语句的作用就是把这个单元里的所有“工具”引入到你当前的代码文件中让你可以直接使用而无需自己从头再写一遍。这就像你要组装一台电脑不需要自己从炼硅开始造CPU直接去市场上买现成的英特尔或AMD的处理器来用就行。import就是那个“购买并使用”的过程。为什么这很重要第一是代码复用避免重复造轮子。Python社区有海量的第三方模块库几乎涵盖了所有你能想到的领域从科学计算到网络爬虫从图形界面到机器学习。第二是命名空间管理防止命名冲突。你自己写的函数叫open()Python内置的也有个open()通过模块前缀如os.open()就能清晰区分。第三是结构清晰将大型项目分解为一个个小模块各司其职便于协作和维护。理解了import的必要性我们再来看看它的几种常见用法这直接关系到你代码的整洁度和运行效率。1.1 import的四种姿势从基础到高效最直接的方式是import module_name。这会导入整个模块使用时需要带上模块名作为前缀。import time print(time.time()) # 获取当前时间戳这种方式清晰明了一眼就能看出time()函数来自time模块。但如果你频繁使用某个模块里的特定函数每次都写前缀会有点啰嗦。这时可以用from module_name import function_name。from time import time, sleep print(time()) # 现在可以直接用time()而不需要time.time() sleep(1) # 让程序暂停1秒这很方便但要注意命名污染。如果你从不同模块导入了同名的函数后导入的会覆盖先导入的。更激进的做法是from module_name import *这会导入模块中所有不以_开头的名称。我强烈建议你避免这种写法因为它会让当前命名空间变得混乱不堪你很难知道一个函数到底是从哪来的调试起来会是噩梦。对于名字很长的模块我们可以使用import module_name as alias来给它起个别名。import numpy as np import pandas as pd这是数据科学领域的标准做法np和pd已成共识既缩短了代码又保持了可读性。那么Python解释器是怎么找到这些模块的呢当你执行import something时解释器会按顺序搜索一系列目录这个列表存储在sys.path变量里。它通常包括当前脚本所在的目录。环境变量PYTHONPATH中列出的目录。Python安装路径下的标准库目录如site-packages。如果你自己写了一个模块my_module.py想在其他项目中导入最简单的方法就是把它放在和你的主脚本同一个目录下或者将其路径添加到sys.path中。一个常见的错误是ModuleNotFoundError: No module named xxx。这通常意味着模块名拼写错误。模块没有安装对于第三方库需要用pip install来安装。模块不在sys.path包含的任何一个目录里。搞清楚了import的机制我们就可以开始使用Python标准库中那些强大而实用的模块了。time、os、random就是其中使用频率最高的几个它们能让你快速实现时间处理、系统交互和随机操作。2. 与时间共舞深入time模块的实用场景时间处理是编程中最常见的需求之一无论是记录日志、定时任务还是测量性能都离不开它。Python的time模块提供了各种与时间相关的函数但初看可能会觉得有些混乱。其实我们可以把时间分为三种主要“形态”时间戳、结构化时间和可读字符串。时间戳是计算机最理解的时间形式它是一个浮点数表示自1970年1月1日00:00:00 UTC纪元以来的秒数。time.time()返回的就是当前时间戳。它的优点是计算方便适合进行时间的加减和比较。import time start time.time() # 记录开始时间戳 # 模拟一些耗时操作 time.sleep(0.5) # 让程序休眠0.5秒 end time.time() # 记录结束时间戳 print(f操作耗时{end - start:.2f}秒) # 计算并打印耗时结构化时间是一个9元组它把时间拆解成年、月、日、时、分、秒、一周第几日、一年第几日、夏令时等组件。time.localtime()将时间戳转换为本地时间的结构time.gmtime()则转换为UTC时间的结构。当你需要获取时间的某个特定部分时比如只要“小时”它就非常有用。now_struct time.localtime() print(f今年是 {now_struct.tm_year} 年) print(f今天是本周的第 {now_struct.tm_wday 1} 天) # tm_wday范围是0-60代表周一可读字符串是我们人类最喜欢的形式。time.ctime()可以把一个时间戳直接转换成Mon Apr 15 14:30:00 2024这样的字符串。而time.strftime()则提供了强大的格式化能力让你可以自定义输出格式。# 使用ctime快速转换 print(time.ctime()) # 输出类似Mon Apr 15 14:30:00 2024 # 使用strftime自定义格式 formatted_time time.strftime(%Y-%m-%d %H:%M:%S, time.localtime()) print(f当前时间{formatted_time}) # 输出2024-04-15 14:30:00这里%Y代表四位数的年%m代表月%d代表日%H是24小时制的小时%M是分%S是秒。完整的格式代码可以在Python官方文档中找到。2.1 性能剖析与程序暂停time模块的进阶技巧除了获取时间time模块在性能优化和流程控制上也扮演着关键角色。time.perf_counter()和time.process_time()是两个用于高精度计时的函数但它们有细微差别。time.perf_counter()返回一个具有最高可用分辨率的性能计数器的值用于测量短时间间隔。它会包含系统睡眠的时间适合用来测量代码段的实际经过的墙钟时间。time.process_time()则返回当前进程的系统和用户CPU时间之和。它不包括睡眠时间只计算进程真正使用CPU的时间。所以如果你想测量一段CPU密集型代码的纯计算开销process_time()更合适。import time def heavy_computation(): sum 0 for i in range(10**7): sum i return sum # 测量墙钟时间 start_wall time.perf_counter() result heavy_computation() end_wall time.perf_counter() print(f墙钟时间: {end_wall - start_wall:.4f} 秒) # 测量CPU时间 start_cpu time.process_time() result heavy_computation() end_cpu time.process_time() print(fCPU时间: {end_cpu - start_cpu:.4f} 秒)你会发现在程序没有休眠、全力计算时两者差距很小。但如果代码中包含time.sleep()差别就大了。说到time.sleep(seconds)它用于让当前线程暂停指定的秒数。这个函数在编写需要等待、轮询或控制频率的脚本时非常有用。比如爬虫请求网站时为了避免请求过快被反爬通常会在每次请求间插入sleep。注意time.sleep()的精度取决于操作系统。在大多数系统上它无法保证精确到毫秒或微秒级别的暂停尤其是当系统负载很高时。对于需要高精度定时任务如音频采样、高频交易建议使用专门的调度库或研究操作系统的实时时钟接口。3. 打通Python与操作系统的桥梁os模块实战如果说time模块让Python具备了时间感知能力那么os模块则赋予了它与操作系统对话的“手脚”。通过os模块你的Python脚本可以像在命令行中一样操作文件、目录、环境变量甚至运行其他程序。最基础也最常用的莫过于文件和目录操作。os.getcwd()可以获取当前工作目录os.chdir(path)则可以改变它这相当于命令行里的cd命令。import os print(f当前工作目录{os.getcwd()}) os.chdir(/tmp) # 切换到/tmp目录Linux/macOS或C:\TempWindows print(f切换后目录{os.getcwd()})列出目录内容使用os.listdir(path)它返回一个包含目录下所有文件和子目录名称的列表。如果你想区分文件和目录或者需要更详细的信息如大小、修改时间则需要配合os.path模块或使用os.scandir()后者性能更好。创建目录有os.mkdir(path)创建单级目录和os.makedirs(path, exist_okTrue)递归创建多级目录。exist_okTrue参数非常实用它允许在目录已存在时不抛出FileExistsError异常让你的代码更健壮。# 安全地创建多级目录 target_dir ./project/data/logs os.makedirs(target_dir, exist_okTrue)文件操作方面os.rename(src, dst)用于重命名或移动文件os.remove(path)用于删除文件。删除目录则需要os.rmdir(path)但它只能删除空目录。要删除非空目录可以使用更强大的shutil.rmtree()来自shutil模块。3.1 路径处理的“瑞士军刀”os.path子模块在操作文件和目录时处理路径字符串是个高频且容易出错的任务。直接拼接字符串会遇到跨平台分隔符/vs\的问题。os.path子模块提供了一系列函数来优雅地处理路径。os.path.join(a, b, c...)智能地拼接多个路径组件使用当前操作系统的正确分隔符。os.path.abspath(path)将相对路径转换为绝对路径。os.path.dirname(path)返回路径的目录名。os.path.basename(path)返回路径的文件名或最后一级目录名。os.path.exists(path)判断路径是否存在。os.path.isfile(path)/os.path.isdir(path)判断路径是文件还是目录。os.path.getsize(path)获取文件大小字节。import os.path # 安全的路径拼接 config_path os.path.join(etc, myapp, config.ini) print(f配置文件路径{config_path}) # 在Linux上输出 etc/myapp/config.ini在Windows上输出 etc\myapp\config.ini # 检查并读取文件 if os.path.exists(config_path) and os.path.isfile(config_path): file_size os.path.getsize(config_path) print(f配置文件存在大小为 {file_size} 字节) # 这里可以继续用open()读取文件内容 else: print(配置文件不存在或不是文件)3.2 环境变量与执行系统命令os模块还能让你访问和修改环境变量这是配置程序行为的一种常见方式。os.environ是一个类似字典的对象包含了所有环境变量。import os # 获取环境变量 home_dir os.environ.get(HOME) # Linux/macOS # 或者 os.environ.get(USERPROFILE) # Windows print(f用户家目录{home_dir}) # 设置环境变量仅对当前进程及其子进程有效 os.environ[MY_APP_MODE] DEBUG最后os.system(command)允许你执行一条系统shell命令。例如你想在Python脚本里快速打开一个文件或网站# 在macOS或Linux上打开一个文本文件 os.system(open /path/to/file.txt) # macOS # os.system(xdg-open /path/to/file.txt) # Linux # os.system(start notepad C:\\path\\to\\file.txt) # Windows注意os.system()虽然方便但存在安全隐患命令注入且难以获取命令的输出。对于更复杂的交互推荐使用subprocess模块它提供了更强大、更安全的接口来生成新进程、连接到输入/输出/错误管道并获取返回码。4. 制造“不确定性”的艺术random模块全解析从游戏中的骰子到抽奖程序再到机器学习中的随机初始化random模块为Python程序注入了“随机”的灵魂。但需要明确一点计算机生成的随机数本质上是伪随机数它们由一个确定的算法伪随机数生成器PRNG根据一个初始的“种子”计算出来。只要种子相同生成的随机数序列就完全一样。random.seed(aNone)函数就是用来设置这个种子的。import random random.seed(42) # 设置种子为42 print(random.random()) # 第一次调用输出一个固定的数比如0.6394267984578837 print(random.random()) # 第二次调用输出序列中的下一个固定数 random.seed(42) # 重置种子为42 print(random.random()) # 输出和第一次完全相同的数0.6394267984578837设置种子在需要重现结果的场景下非常有用比如科学实验、机器学习模型训练确保每次运行都能得到相同的“随机”数据便于调试和验证。如果不设置种子默认会使用系统时间这样每次运行结果就不同了。random.random()是最核心的函数它返回一个[0.0, 1.0)范围内的随机浮点数。基于它衍生出了一系列实用函数。4.1 生成特定范围的随机数与随机选择random.randint(a, b)返回一个[a, b]范围内的随机整数包含两端。模拟掷骰子就是random.randint(1, 6)。random.uniform(a, b)返回一个[a, b]范围内的随机浮点数。random.randrange(start, stop[, step])类似于range()函数从指定的范围内按照给定的步长随机选择一个数。random.randrange(0, 101, 2)会从0到100的偶数中随机选一个。随机选择是另一个常见需求。random.choice(seq)从一个非空序列列表、元组、字符串中随机选择一个元素。fruits [apple, banana, orange, grape] today_fruit random.choice(fruits) print(f今天吃{today_fruit})random.choices(population, weightsNone, k1)功能更强大可以进行有放回的随机抽样并可以指定权重。weights参数是一个与population等长的序列表示每个元素被选中的相对概率。k指定抽取次数。# 抽奖一等奖概率10%二等奖30%三等奖60% prizes [一等奖, 二等奖, 三等奖] weights [0.1, 0.3, 0.6] result random.choices(prizes, weightsweights, k10) # 抽10次 print(f十次抽奖结果{result})而random.sample(population, k)则是进行无放回的随机抽样确保抽到的k个元素都是不同的。这常用于洗牌或从列表中随机选取若干不重复的项。# 从52张扑克牌中随机发5张不重复的牌 deck list(range(1, 53)) # 用1-52代表52张牌 hand random.sample(deck, k5) print(f你的手牌是{hand})4.2 随机打乱与随机分布random.shuffle(x)函数会将一个可变序列如列表中的元素随机打乱顺序原地修改原序列。这正是洗牌算法的实现。cards [A, 2, 3, K, Q, J] random.shuffle(cards) print(f洗牌后{cards})注意random.shuffle()只作用于可变序列如列表。对于不可变序列如元组、字符串你需要先将其转换为列表打乱后再转回去。除了均匀分布random模块还提供了其他几种常见的概率分布这在模拟和统计中非常有用。random.gauss(mu, sigma)/random.normalvariate(mu, sigma)生成服从高斯正态分布的随机浮点数mu是均值sigma是标准差。random.expovariate(lambd)生成服从指数分布的随机浮点数lambd是率参数1.0除以均值。例如模拟一个服务中心的客户到达间隔时间通常服从指数分布average_interval 5.0 # 平均间隔5分钟 next_arrival_time random.expovariate(1.0 / average_interval) print(f下一位客户将在约 {next_arrival_time:.2f} 分钟后到达)5. 模块组合实战构建一个自动化文件整理脚本掌握了import、time、os、random这几个模块我们已经可以做一些有趣且实用的小项目了。让我们把这些知识串联起来编写一个简单的自动化文件整理脚本。这个脚本会监控一个下载文件夹将其中一周前的文件自动移动到一个“归档”目录并在移动完成后随机选择一个幸运文件在日志中为其“点赞”。这个项目将综合运用os模块遍历目录、检查文件属性、创建目录、移动文件。time模块获取文件修改时间并与当前时间比较。random模块从文件中随机选择一个。5.1 设计脚本逻辑与核心函数首先我们规划一下脚本的步骤定义需要监控的源目录如下载目录和目标归档目录。计算“一周前”的时间点当前时间戳减去7天的秒数。遍历源目录下的所有文件暂不处理子目录。对于每个文件获取其最后修改时间。如果修改时间早于“一周前”的时间点则将其移动到归档目录。记录所有被移动的文件。移动完成后如果存在被移动的文件则随机选择一个在日志中记录一条趣味信息。我们首先实现一个核心函数用于判断文件是否“过期”超过指定天数。import os import time import random import shutil # 用于移动文件跨设备移动比os.rename更可靠 from datetime import datetime, timedelta def is_file_older_than(filepath, days): 判断文件是否早于指定的天数。 参数 filepath: 文件路径 days: 天数 返回 bool: 如果文件最后修改时间早于当前时间 - days天返回True否则False。 if not os.path.isfile(filepath): return False # 获取文件的最后修改时间戳 file_mtime os.path.getmtime(filepath) # 计算截止时间戳当前时间 - days天 cutoff_time time.time() - (days * 24 * 60 * 60) # 比较 return file_mtime cutoff_time5.2 实现主流程与异常处理接下来我们实现主函数包含目录准备、文件遍历、移动和随机选择逻辑。def organize_old_files(source_dir, archive_dir, days_old7): 整理旧文件的主函数。 参数 source_dir: 需要整理的源目录 archive_dir: 归档目录 days_old: 超过多少天的文件需要被归档 # 1. 确保归档目录存在 os.makedirs(archive_dir, exist_okTrue) print(f源目录{source_dir}) print(f归档目录{archive_dir}) print(f正在查找超过{days_old}天的文件...) # 2. 遍历源目录 moved_files [] try: for filename in os.listdir(source_dir): filepath os.path.join(source_dir, filename) # 只处理文件忽略目录 if os.path.isfile(filepath): if is_file_older_than(filepath, days_old): # 构造目标路径 dest_path os.path.join(archive_dir, filename) # 处理目标文件已存在的情况在文件名后添加时间戳 if os.path.exists(dest_path): name, ext os.path.splitext(filename) timestamp datetime.now().strftime(%Y%m%d_%H%M%S) new_filename f{name}_{timestamp}{ext} dest_path os.path.join(archive_dir, new_filename) # 移动文件 shutil.move(filepath, dest_path) moved_files.append(dest_path) # 记录移动后的新路径 print(f 已移动{filename} - {os.path.basename(dest_path)}) except PermissionError as e: print(f权限错误无法访问文件{e}) except OSError as e: print(f系统错误{e}) # 3. 总结与“幸运文件”选择 print(- * 40) if moved_files: print(f整理完成共移动了 {len(moved_files)} 个文件。) # 随机选择一个“幸运文件” lucky_file random.choice(moved_files) print(f 今天的幸运文件是{os.path.basename(lucky_file)}) print(f 它曾被遗忘在下载文件夹超过{days_old}天现在已在归档区获得新生) # 可以将这条信息写入一个日志文件 log_message f{datetime.now()}: 幸运文件 - {lucky_file}\n with open(os.path.join(archive_dir, cleanup.log), a, encodingutf-8) as f: f.write(log_message) else: print(没有找到需要移动的旧文件。)5.3 脚本的配置与运行最后我们配置目录并运行脚本。你需要将SOURCE_DIR和ARCHIVE_DIR替换成你电脑上的实际路径。if __name__ __main__: # 配置路径请根据你的系统修改 # Windows 示例 # SOURCE_DIR rC:\Users\YourName\Downloads # ARCHIVE_DIR rC:\Users\YourName\Downloads\Archive # macOS / Linux 示例 SOURCE_DIR /Users/YourName/Downloads ARCHIVE_DIR /Users/YourName/Downloads/Archive # 运行整理函数默认清理7天前的文件 organize_old_files(SOURCE_DIR, ARCHIVE_DIR, days_old7)这个脚本展示了如何将多个标准库模块协同工作解决一个实际问题。你可以通过Windows的任务计划程序或macOS/Linux的cron定时任务让这个脚本定期自动运行实现真正的自动化整理。在实际使用中你可能会考虑更多细节比如是否要递归处理子目录、是否按文件类型分类归档、如何处理同名文件冲突等。但无论如何os、time、random这三个模块都是你构建此类文件系统自动化工具最坚实的基础。通过这个项目你应该能体会到掌握这些基础模块就能让Python脚本从简单的计算器进化成能与你操作系统环境智能交互的得力助手。