读取整个文件内容为字符串(最常用)
这是最基础的需求,比如你想读取一个 .py 文件的内容,然后进行分析、搜索或者直接打印。

方法:使用 with open() 语句
这是 Python 官方推荐的文件读取方式,因为它能确保文件在操作完成后被自动关闭,即使发生错误也不例外。
示例代码:
假设你有一个名为 my_module.py 的文件,内容如下:
# my_module.py
def greet(name):
"""这是一个简单的问候函数"""
return f"Hello, {name}!"
VERSION = "1.0.0"
__author__ = "John Doe"
你创建另一个文件 read_file.py 来读取它的内容:

# read_file.py
file_path = 'my_module.py'
try:
# 使用 'r' 模式(读取模式)和 encoding='utf-8' 是个好习惯
with open(file_path, 'r', encoding='utf-8') as f:
# 读取整个文件内容到一个字符串变量中
content = f.read()
# 打印读取到的内容
print("--- 文件内容 ---")
print(content)
print("--- 内容结束 ---")
# 你现在可以对 content 字符串进行任何操作
# 检查版本信息是否存在
if 'VERSION' in content:
print("\n在文件中找到了 'VERSION' 关键字。")
except FileNotFoundError:
print(f"错误:文件 '{file_path}' 未找到。")
except Exception as e:
print(f"读取文件时发生错误: {e}")
运行 read_file.py 的输出:
--- 文件内容 ---
# my_module.py
def greet(name):
"""这是一个简单的问候函数"""
return f"Hello, {name}!"
VERSION = "1.0.0"
__author__ = "John Doe"结束 ---
在文件中找到了 'VERSION' 关键字。
逐行读取文件内容
当处理非常大的文件时,一次性读取整个文件可能会消耗大量内存,这时,逐行读取是更好的选择。
方法:直接遍历文件对象
文件对象本身就是一个迭代器,可以直接在 for 循环中使用。
示例代码:
# read_file_line_by_line.py
file_path = 'my_module.py'
try:
with open(file_path, 'r', encoding='utf-8') as f:
print("--- 逐行打印文件内容 ---")
for line in f:
# line 变量会包含每一行的文本,包括末尾的换行符 \n
# 使用 .strip() 可以去除首尾的空白字符(包括换行符)
print(line.strip())
print("--- 逐行打印结束 ---")
except FileNotFoundError:
print(f"错误:文件 '{file_path}' 未找到。")
运行 read_file_line_by_line.py 的输出:
--- 逐行打印文件内容 ---
# my_module.py
def greet(name):
"""这是一个简单的问候函数"""
return f"Hello, {name}!"
VERSION = "1.0.0"
__author__ = "John Doe"
--- 逐行打印结束 ---
执行目标 Python 文件并获取其变量或函数的值
这是一种更高级的用法,你不仅仅是读取文件内容,而是运行这个文件,并像导入模块一样获取它的命名空间(变量、函数、类等)。
方法:使用 importlib 模块
importlib 是 Python 的标准库,提供了比 import 语句更底层的模块控制功能。
重要提示: 这种方法会执行目标文件中的所有代码! 如果目标文件有副作用(如打印信息、修改文件、连接网络等),这些副作用都会发生,请确保你信任要执行的文件。
示例代码:
我们仍然使用上面的 my_module.py。
# import_and_run_module.py
import importlib.util
import sys
def import_module_from_file(file_path):
"""从指定文件路径导入一个模块"""
# 获取模块的规范名称
module_name = "dynamic_module" # 可以是任意你想要的名称
# 如果模块已经导入,则重新加载它
if module_name in sys.modules:
importlib.reload(sys.modules[module_name])
return sys.modules[module_name]
# 创建模块的规范
spec = importlib.util.spec_from_file_location(module_name, file_path)
if spec is None:
raise ImportError(f"无法从 '{file_path}' 创建模块规范")
# 创建模块
module = importlib.util.module_from_spec(spec)
# 将模块添加到 sys.modules 中(可选,但推荐)
sys.modules[module_name] = module
# 执行模块的代码(这是关键步骤!)
spec.loader.exec_module(module)
return module
# --- 使用 ---
if __name__ == "__main__":
file_path = 'my_module.py'
try:
# 动态导入 my_module.py
my_module = import_module_from_file(file_path)
print(f"成功从 '{file_path}' 导入模块!")
print(f"模块名称: {my_module.__name__}")
# 现在你可以像使用普通模块一样访问它的内容
print("\n--- 获取模块中的变量 ---")
print(f"VERSION: {my_module.VERSION}")
print(f"__author__: {my_module.__author__}")
print("\n--- 调用模块中的函数 ---")
greeting = my_module.greet("Alice")
print(greeting)
except FileNotFoundError:
print(f"错误:文件 '{file_path}' 未找到。")
except Exception as e:
print(f"导入或执行模块时发生错误: {e}")
运行 import_and_run_module.py 的输出:
成功从 'my_module.py' 导入模块!
模块名称: dynamic_module
--- 获取模块中的变量 ---
VERSION: 1.0.0
__author__: John Doe
--- 调用模块中的函数 ---
Hello, Alice!
解析 Python 文件为抽象语法树
如果你需要分析 Python 文件的代码结构,而不是简单地读取或执行它(想自动提取函数名、注释、类定义等),你需要将文件解析成抽象语法树。
方法:使用 ast (Abstract Syntax Trees) 模块
ast 模块可以将 Python 源代码字符串转换成一个树状结构,你可以遍历这个树来分析代码。
示例代码:
# parse_ast.py
import ast
file_path = 'my_module.py'
try:
with open(file_path, 'r', encoding='utf-8') as f:
source_code = f.read()
# 将源代码解析为 AST
tree = ast.parse(source_code, filename=file_path)
# 定义一个访问者类来遍历 AST
class MyCodeVisitor(ast.NodeVisitor):
def visit_FunctionDef(self, node):
"""当访问到函数定义时调用"""
print(f"发现函数: {node.name} (在第 {node.lineno} 行)")
# 可以继续访问函数体
self.generic_visit(node)
def visit_Assign(self, node):
"""当访问到赋值语句时调用"""
# 获取赋值的变量名
for target in node.targets:
if isinstance(target, ast.Name):
print(f"发现变量赋值: {target.id} = ... (在第 {node.lineno} 行)")
self.generic_visit(node)
def visit_Expr(self, node):
"""当访问到表达式语句时调用"""
# 检查是否是字符串字面量(可能是文档字符串)
if isinstance(node.value, ast.Constant) and isinstance(node.value.value, str):
print(f"发现文档字符串: {node.value.value} (在第 {node.lineno} 行)")
self.generic_visit(node)
# 创建访问者实例并遍历 AST
visitor = MyCodeVisitor()
visitor.visit(tree)
except FileNotFoundError:
print(f"错误:文件 '{file_path}' 未找到。")
except SyntaxError as e:
print(f"文件 '{file_path}' 包含语法错误: {e}")
except Exception as e:
print(f"解析文件时发生错误: {e}")
运行 parse_ast.py 的输出:
发现文档字符串: 这是一个简单的问候函数 (在第 3 行)
发现函数: greet (在第 2 行)
发现变量赋值: VERSION = ... (在第 6 行)
发现变量赋值: __author__ = ... (在第 7 行)
总结与选择
| 场景 | 目标 | 推荐方法 | 优点 | 缺点/注意事项 |
|---|---|---|---|---|
| 简单读取 | 获取文件的全部文本内容 | with open(...) as f: f.read() |
简单、直接、高效 | 不适合处理超大文件(内存问题) |
| 逐行处理 | 处理大文件或逐行分析 | with open(...) as f: for line in f: |
内存占用低,适合流式处理 | 逻辑上需要逐行处理 |
| 执行代码 | 运行文件并获取其变量/函数 | importlib |
功能强大,能获取运行时结果 | 会执行代码,有安全风险 |
| 分析结构 | 提取函数、类、注释等代码元信息 | ast 模块 |
精准分析代码结构,无需执行 | 学习曲线稍陡,处理 AST 较复杂 |
根据你的具体需求选择最合适的方法,对于大多数日常任务,场景一和场景二已经足够,只有在需要动态加载或分析代码时,才需要用到 场景三和场景四。
