Mendelevium
Diary
Drug Design
Field Knowledge
Academia
Yang
Biology
Physics
Free Energy
Machine Learning & AI
Active Learning
Basics
Boltz-2
Data
Generation
Interpretability
QSAR application
Representations
Mol2Image
Workflow & Agent
Molecular Dynamics
FF & Algorithm
Small Molecule
martini
water
Interaction
Modeling & Tools
QM
Sampling & Analysis
Allostery
Fundamental
Other
Specific Sytems
Enzyme Engineering
Fiber & LLPS
Membrane
orientation_penetration
Metal
Nano Polymers
Skin Permeation
Techniques
Linux
Python
Research
Web
about
Home
Contact
Copyright © 2025 Xufan Gao | Academic Research Blog
Home
>
Techniques
> Python
A Bunch of Biophysics is Loading ...
Python
【笔记整理|2024-07】Python开发环境构建与性能优化:从编码规范到科学计算
【笔记整理|2024-07】Python开发环境构建与性能优化:从编码规范到科学计算 引言 Python作为科学计算和数据科学的主要编程语言,其开发环境的配置和性能优化直接影响研究效率。本文整理了从技术讨论中提取的Python开发环境构建、性能优化和科学计算的实用技巧,涵盖从编码规范到高级性能优化的各个方面。 Python编码最佳实践 属性访问与动态操作 Python提供了灵活的属性访问和动态操作机制: 在Python中,如果你想要根据传递的变量动态地设置对象的属性值,可以使用setattr函数。 In Python, the getattr method is called when you try to access an attribute that does not exist, but it’s not a standard way to access attributes. Instead, you typically access attributes using the dot notation (e.g., object.attribute). 迭代器优化 在Python中,前置和后置增量操作的性能差异值得注意: To be accurate: ++i can sometimes be faster than i++ and is never slower. For fundamental data types, the compiler will very likely fix your mistake and optimise away any unneeded copying. For iterators this is more difficult and for user-defined types it may very well be impossible. 排序算法与数据结构 Python内置的排序算法和数据结构特性: 在Python 中,内置的 sorted() 函数使用的是双轴快排算法(timsort)来对序列进行排序。 这种算法的时间复杂度在最坏情况下是O(n * log n),平均情况下是O(n * log n) n * log n + a * log n ≈ n * log n < n * a log2 or ln? 哈希表与集合操作 理解Python中集合和字典的内部实现有助于性能优化: 是的,集合和字典在Python中都是通过哈希表实现的。对于集合和字典的元素或键的查找,时间复杂度通常是O(1),这是因为哈希表使得元素的位置可以快速定位。 Python性能分析 代码性能分析工具 Python提供了多种性能分析工具来识别性能瓶颈: 在Python中,你可以使用cProfile模块来分析每个函数的执行时间123。以下是一个示例: 性能分析输出示例: update_results 2 96579 66 实际性能对比 实际测试显示不同运行环境下的性能差异: pycharm profile says 71s,simply debug 56s, cmd just 31s other causes, fit: ~8s; concat: 6s process_dict 11.6s, including the two? 数据处理与优化策略 Pandas数据处理 Pandas是Python数据分析的核心库,掌握其高级功能非常重要: df = df_input.copy(deep=True) # Use pandas’ built-in copy method 大规模数据优化 处理大规模数据时,性能优化尤为重要: Optimal pipeline for huge data: fast_histogram + memory mapping fast_histogram doesn’t require parallel processing as it’s already optimized internally 字符串处理 字符串处理在数据分析中经常是性能瓶颈: transform the code into a clean, efficient, and maintainable analysis framework. 科学计算环境配置 包管理工具 合理的包管理策略可以避免依赖冲突: pip install -e .[dev] Conda环境管理 Conda是科学计算环境管理的首选工具: conda install conda-forge::libmamba 要查看pip的缓存路径,可以使用pip cache dir命令。在命令行或终端中输入该命令,pip会显示其缓存的目录。 环境共享 在多用户环境中共享conda环境可以提高效率: 看起来你想将用户 xucx 的 boltz2 Conda 环境共享给其他用户,让大家都能方便地通过 conda activate boltz2 来使用。最直接且对原用户影响较小的方式是创建符号链接。 Python科学计算生态 科学计算库 Python拥有丰富的科学计算库生态系统: import deepchem as dc 数据可视化 数据可视化是科学计算的重要组成部分: In Matplotlib, the axes can be easily hidden by calling the set_visible() method on the axes object and setting it to False. This can be done either by using the axes object itself or by looping through the list of axes in a figure. 色彩映射与数据表达 合适的色彩映射可以增强数据的可读性: In the context of seaborn.diverging_palette(), h_neg and h_pos refer to the anchor hues that define the endpoints of the color spectrum for the diverging palette. These hues are specified in the HUSL (Hue, Saturation, Lightness) color space, where hue is an angle on the color wheel ranging from 0 to 360 degrees. 高级可视化技术 高级可视化技术可以更好地展示复杂数据: https://medium.com/@alexbelengeanu/getting-started-with-raincloud-plots-in-python-2ea5c2d01c11 开发工具与环境配置 代码编辑器配置 合适的代码编辑器配置可以提高开发效率: 打开VSCode,并在左侧的文件资源管理器中选择你要检索字符串的项目文件夹。 2. 使用快捷键Ctrl+Shift+F,或者点击顶部菜单栏中的”查找” -> “查找”来打开查找面板。 3. 在查找面板的文本输入框中输入你要搜索的字符串。 你可以使用普通的文本字符串进行搜索,也可以使用正则表达式进行更高级的搜索。 PyCharm 本身是一个代码编辑器(IDE),而不是一个网页浏览器。所以它不能像 Chrome 或 Edge 那樣直接”打开”并渲染 localhost:8501 的页面内容。 前端开发与后端集成 Python在现代Web开发中也有广泛应用: 我将使用Tailwind CSS进行布局和样式设计,并采用Chart.js(用于标准图表)和Plotly.js(如果需要更复杂的图表,并确保使用Canvas/WebGL渲染)来创建可视化内容。所有图表和图示都将严格遵守无SVG和无Mermaid JS的要求,转而使用HTML/CSS、Unicode字符或Canvas来实现。 I designed a frontend to manage the analysis and figures. here’s the overview. understand it Python包管理与发布 包缓存管理 合理管理包缓存可以节省磁盘空间并提高安装速度: 要清理pip的缓存,可以使用pip cache purge命令。这将清除pip缓存的所有内容,包括已下载但未安装的包和已安装但未使用的包的缓存。如果只想清除特定包的缓存,可以使用pip cache remove 命令,将package_name替换为要清除缓存的包名。 Git与代码版本控制 版本控制是现代软件开发的标准实践: git config advice.addIgnoredFile false git config –global user.name “gxf1212” 文档生成与部署 Sphinx文档系统 Sphinx是Python项目文档生成的标准工具: How do I serve sphinx documentation locally? 用claude code写文案可能会有点过于浪费了 静态网站生成 现代文档部署通常使用静态网站生成器: 📚 Complete Workflow: Public Documentation with Private 高级编程技巧 正则表达式应用 正则表达式是文本处理的强大工具: 要查找目录名中恰好包含两个连字符的目录,需要将grep模式”锚定”以匹配整行。 代码重构与优化 代码重构是提高代码质量的重要手段: transform the code into a clean, efficient, and maintainable analysis framework. 函数设计与最佳实践 良好的函数设计是高质量代码的基础: The most straightforward and conventional method is to prefix each line of the desired comment block with the hash symbol (#). Python与AI集成 AI辅助开发 AI工具正在改变Python开发的方式: Act as an expert Python developer and help to design and create code blocks / modules as per the user specification. I asked ChatGPT about this, it says: Claude Code集成 Claude Code为Python开发提供了AI辅助: https://www.yuque.com/beihu-iq2oo/zlyf06/vlg45fk72pu9gmtk?singleDoc#%20%E3%80%8AClaude%20Code%EF%BC%9A%E8%AE%A1%E8%B4%B9%E4%B8%8E%E8%AE%A2%E9%98%85%E3%80%8B Claude Code:计费与订阅 AICodemirror,必须curl -fsSL https://download.aicodemirror.com/env_deploy/env-deploy.sh bash -s – “sk-ant-api03-JQBd6V2vGYfPrl20II1Y3mGvRoK52kP7BJKUPSh4jCSoou4Jxw7ctQ3lVFJQ36tTO10cypFIIU8MYgbQ_78E3g”之后才能用 What the Script Does: After setting the environment variables, the script finds your API key, takes the last 20 characters of it, and uses the jq command to add this snippet to a list inside the ~/.claude.json file. Specifically, it adds it to the customApiKeyResponses.approved array. must do this after sudo npm install -g @anthropic-ai/claude-code 环境配置脚本 自动化环境配置脚本可以简化开发环境搭建: (cat ~/.claude.json 2>/dev/null echo ‘null’) jq –arg key “${ANTHROPIC_API_KEY: -20}” ‘(. // {}) .customApiKeyResponses.approved = (.[], $key) unique)’ > ~/.claude.json.tmp && mv ~/.claude.json.tmp ~/.claude.json 实用编程技巧 文件操作技巧 高效的文件操作是数据处理的基础: Working with Zip Files zip s.zip software-copyright/ -r 系统命令集成 Python与系统命令的集成可以扩展功能: 03:14:40 base gxf1212@gxf-pop-os file-transfer → gnome-shell –version to fix https://extensions.gnome.org/extension/1160/dash-to-panel/ 条件判断与逻辑 良好的条件判断逻辑可以提高代码的健壮性: for what it’s worth 总结与最佳实践 编码规范:遵循Python编码规范,使用合适的属性访问方式和动态操作 性能优化:熟练使用性能分析工具,理解Python内部数据结构的实现原理 环境管理:合理使用conda和pip管理Python环境,解决依赖冲突 科学计算:掌握Python科学计算生态,包括数据处理、可视化和分析工具 开发工具:配置合适的开发环境,使用现代化的编辑器和工具链 版本控制:建立良好的Git使用习惯,确保代码的可追溯性 文档生成:使用Sphinx等工具生成高质量的项目文档 AI集成:合理利用AI工具提高开发效率,但不过度依赖 通过这些Python开发技巧的掌握,可以显著提高科学计算和数据处理的效率和质量。 参考资源 雨云图Python教程 Claude Code使用指南 文件压缩操作指南 GNOME扩展修复 VS Code搜索功能文档
Techniques
· 2025-10-11
Pytest Deep Dive Tutorial: Beginner-Friendly Guide to Python Testing
Pytest 深度入门教程 (初学者友好版) pytest 是一个功能丰富、易于使用且非常流行的 Python 测试框架。与 Python 内置的 unittest 模块相比,pytest 的语法更简洁、更灵活,并且拥有庞大的插件生态系统,能够极大地提升你的测试效率和体验。 想象一下,你是一位大厨,需要确保每一道菜品都符合标准。测试代码就像是品尝和检验菜品的过程,而 pytest 就是一套能帮你高效完成这个过程的顶级厨具和标准化流程。 为什么选择 Pytest? 简单易学,上手快: 你不需要学习复杂的类结构,直接使用标准的 Python 函数来编写测试。 断言(检查条件是否为真)直接使用 Python 内置的 assert 语句,非常直观。 强大的断言功能: pytest 对 assert 语句进行了智能处理。当断言失败时,它会提供非常详细的上下文信息,告诉你哪里出了错,以及相关变量的当前值,极大地帮助调试。 自动发现测试: 你只需要遵循简单的命名约定,pytest 就能自动找到你的测试文件和测试函数,无需手动注册。 丰富的插件生态系统: 拥有大量开箱即用的插件,例如: pytest-cov: 用于生成测试覆盖率报告。 pytest-xdist: 用于并行执行测试,加快测试速度。 pytest-django, pytest-flask: 用于集成主流Web框架。 还有更多用于报告、Mocking 等功能的插件。 优雅的 Fixtures (测试固件/夹具): 这是 pytest 的核心特性之一。Fixtures 提供了一种模块化、可重用的方式来管理测试的准备工作(setup)和清理工作(teardown)。你可以把它们看作是测试函数运行前需要准备好的“原材料”或“环境”。 灵活的参数化测试 (Parametrization): 可以非常方便地为同一个测试函数提供多组不同的输入数据和预期输出,避免编写大量重复的测试逻辑。 清晰的测试报告: 默认提供简洁明了的测试报告,通过插件还可以生成更详细的HTML报告。 安装 Pytest 安装 pytest 非常简单,只需要使用 pip: pip install pytest 安装完成后,你就可以在你的项目中使用 pytest 了。 你的第一个 Pytest 测试 pytest 通过遵循特定的命名约定来自动发现测试: 测试文件: 通常命名为 test_*.py (例如 test_calculator.py) 或 *_test.py (例如 calculator_test.py)。 测试函数: 在测试文件中,以 test_ 开头的函数会被识别为测试函数 (例如 def test_addition():)。 测试类 (可选): 如果你喜欢将相关的测试组织在类中,类名应以 Test 开头 (例如 class TestCalculator:),类中的测试方法同样以 test_ 开头。pytest 不需要测试类继承任何特定的基类。 让我们创建一个名为 test_example.py 的文件,并编写一个简单的测试: # test_example.py # 这是我们要测试的函数 def inc(x): return x + 1 # 这是我们的第一个测试函数 def test_increment_positive_number(): # "Arrange" (准备) - 定义输入和预期输出 input_value = 3 expected_value = 4 # "Act" (执行) - 调用被测试的函数 result = inc(input_value) # "Assert" (断言) - 检查结果是否符合预期 assert result == expected_value def test_increment_zero(): assert inc(0) == 1 def test_increment_negative_number(): assert inc(-5) == -4 代码解释: 我们定义了一个简单的函数 inc(x),它将输入值加1。 test_increment_positive_number 是一个测试函数。它遵循了“Arrange-Act-Assert”(AAA)模式: Arrange: 设置测试所需的初始条件和输入。 Act: 执行被测试的代码。 Assert: 验证结果是否与预期相符。 我们直接使用 assert 关键字来声明我们的期望。如果 inc(3) 的结果不等于 4,assert 语句会抛出 AssertionError,pytest 会捕获这个错误并将测试标记为失败。 运行你的测试 打开你的终端或命令行工具,导航到包含 test_example.py 文件的目录,然后简单地运行以下命令: pytest 发生了什么? pytest 会从当前目录开始,递归地查找所有符合命名约定的测试文件 (test_*.py 或 *_test.py)。 在找到的测试文件中,它会查找所有符合命名约定的测试函数 (test_*) 或测试类 (Test*) 中的测试方法。 然后,它会逐个执行这些测试。 最后,它会汇总结果并显示出来。 预期输出 (默认模式): ============================= test session starts ============================== platform ... -- Python ... plugins: ... collected 3 items test_example.py ... [100%] ============================== 3 passed in X.XXs =============================== collected 3 items: pytest 找到了3个测试函数。 test_example.py ...: 每个点 (.) 代表一个通过的测试。如果所有测试都通过,你会看到一串点。 3 passed in X.XXs: 总结信息,告诉你有多少测试通过以及花费的时间。 如果某个测试失败了,比如我们故意修改 test_increment_zero: # test_example.py # ... (其他代码不变) ... def test_increment_zero(): assert inc(0) == 2 # 故意写错,应该是 1 再次运行 pytest,输出会变成: ============================= test session starts ============================== platform ... -- Python ... plugins: ... collected 3 items test_example.py .F. [100%] =================================== FAILURES =================================== ___________________________ test_increment_zero ____________________________ def test_increment_zero(): > assert inc(0) == 2 # 故意写错,应该是 1 E assert 1 == 2 E + where 1 = inc(0) test_example.py:14: AssertionError =========================== short test summary info ============================ FAILED test_example.py::test_increment_zero - assert 1 == 2 ========================= 1 failed, 2 passed in X.XXs ========================== 注意看 FAILURES 部分,pytest 非常清晰地指出了: 哪个测试函数失败了 (test_increment_zero)。 失败的 assert 语句是什么 (assert inc(0) == 2)。 断言失败时的具体值比较 (assert 1 == 2),并且它还告诉我们 1 是 inc(0) 的结果。这种详细的错误报告是 pytest 的一大优势。 理解 -v (详细) 和 -q (静默) 参数 pytest 提供了不同的命令行选项来控制输出的详细程度。 pytest (无参数 - 默认模式): 如上所示,对每个通过的测试显示一个点 (.)。 失败的测试显示 F。 如果测试代码本身有错误(不是断言失败,而是比如语法错误或未捕获的异常),会显示 E。 最后会有一个总结,如果存在失败或错误,会有详细的失败信息。 pytest -v (verbose - 详细模式): 这个选项会为每个测试函数显示其完整的名称以及测试结果 (PASSED, FAILED, ERROR)。 当你有很多测试,并且想清楚地看到每个测试的执行状态时,这个模式非常有用。 pytest -v 如果所有测试都通过,输出示例: ============================= test session starts ============================== platform ... -- Python ... plugins: ... collected 3 items test_example.py::test_increment_positive_number PASSED [ 33%] test_example.py::test_increment_zero PASSED [ 66%] test_example.py::test_increment_negative_number PASSED [100%] ============================== 3 passed in X.XXs =============================== pytest -q (quiet - 静默模式): 这个选项会大幅减少输出信息。 如果所有测试都通过,它通常只输出最后的总结行,甚至可能什么都不输出(除了最终的退出码)。 只有在测试失败或出错时,它才会输出相关的错误信息和总结。 这个模式非常适合在持续集成 (CI) 系统中使用,因为你通常只关心是否有问题发生。 pytest -q 如果所有测试都通过,输出示例可能仅仅是: ============================== 3 passed in X.XXs =============================== 或者,如果CI环境配置为在成功时不输出,你可能什么都看不到。 如果你之前运行 pytest -q 没有看到任何关于测试通过的点的输出,那恰恰说明你的所有测试都成功通过了! -q 的设计目标就是在一切顺利时保持安静。 何时使用哪个参数? 日常开发,快速检查:pytest 想看每个测试的名称和状态,或者调试时:pytest -v 在自动化脚本或CI环境中,只关心失败:pytest -q 使用 assert 进行强大的断言 pytest 最棒的一点就是它允许你直接使用 Python 内置的 assert 语句。当 assert 后面的条件为 False 时,会引发 AssertionError。pytest 会捕获这个错误,将测试标记为失败,并提供非常丰富的调试信息,包括表达式中各个部分的值。 让我们看更多断言的例子。创建一个新文件 test_assertions.py: # test_assertions.py import pytest # 需要导入 pytest 来使用 pytest.raises # 要测试的函数 def get_user_info(user_id): if user_id == 1: return {"name": "Alice", "age": 30, "active": True} elif user_id == 2: return {"name": "Bob", "age": 24, "active": False} else: return None def divide(a, b): if b == 0: raise ValueError("Cannot divide by zero") # 注意:这里我们抛出 ValueError return a / b # 测试函数 def test_user_alice(): alice = get_user_info(1) assert alice is not None assert alice["name"] == "Alice" assert alice["age"] > 25 assert alice["active"] is True # 明确检查布尔值 def test_user_bob_inactive(): bob = get_user_info(2) assert bob["name"].startswith("B") assert not bob["active"] # 另一种检查 False 的方式 assert "email" not in bob # 检查字典中是否不包含某个键 def test_unknown_user(): unknown = get_user_info(99) assert unknown is None def test_division_normal(): assert divide(10, 2) == 5.0 assert divide(7, 2) == 3.5 def test_division_by_zero_custom_error(): # 测试函数是否按预期抛出了特定的异常 # pytest.raises 作为一个上下文管理器使用 with pytest.raises(ValueError) as excinfo: # 捕获 ValueError divide(10, 0) # 可选:检查异常信息是否符合预期 assert "Cannot divide by zero" in str(excinfo.value) def test_list_operations(): my_list = [10, 20, 30, 40] assert 20 in my_list assert 50 not in my_list assert len(my_list) == 4 # Pytest 的断言内省对于比较序列非常有用 # 如果下面这个断言失败了: assert my_list == [10, 20, 35, 40] # Pytest 会告诉你具体哪个元素不同 assert my_list == [10, 20, 30, 40] def test_string_properties(): text = "Pytest is awesome!" assert "awesome" in text assert text.lower() == "pytest is awesome!" assert text.endswith("!") assert len(text.split()) == 3 运行这些测试: pytest test_assertions.py -v 关键点: 丰富的比较信息: 如果 assert alice["name"] == "Bob" 失败了 (因为实际上是 “Alice”),pytest 会告诉你 assert "Alice" == "Bob",让你清楚地看到实际值和期望值的差异。 测试异常 (pytest.raises): 当你期望某段代码抛出特定类型的异常时,使用 pytest.raises。它会捕获预期的异常,如果代码没有抛出该异常,或者抛出了不同类型的异常,测试就会失败。excinfo 对象包含了关于捕获到的异常的详细信息。 涵盖多种数据类型: 你可以用 assert 来检查数字、字符串、列表、字典、布尔值等几乎所有 Python 对象。 参数化测试 (@pytest.mark.parametrize) 当你需要用不同的输入和期望输出来测试同一个函数逻辑时,参数化测试非常有用。它可以避免你编写大量结构相似的测试函数。 你已经在你的 test_single_and_batch 测试中使用了它,这是一个很好的实践! 让我们创建一个 test_parametrize_examples.py 文件: # test_parametrize_examples.py import pytest # 要测试的函数 defis_palindrome(text): if not isinstance(text, str): raise TypeError("Input must be a string") return text.lower() == text.lower()[::-1] # 使用 parametrize @pytest.mark.parametrize("test_input, expected_output", [ ("madam", True), ("racecar", True), ("hello", False), ("Aibohphobia", True), # 测试大小写不敏感 ("", True), # 测试空字符串 (" ", True), # 测试单个空格 ("No lemon, no melon.", False) # 包含标点和空格,按当前函数逻辑会失败 ]) def test_is_palindrome_various_inputs(test_input, expected_output): assertis_palindrome(test_input) == expected_output # 另一个例子:测试数据类型检查 @pytest.mark.parametrize("invalid_input", [ 123, ["list"], None, {"a": 1} ]) def test_is_palindrome_invalid_type(invalid_input): with pytest.raises(TypeError) as excinfo: is_palindrome(invalid_input) assert "Input must be a string" in str(excinfo.value) # 你也可以给每个参数组合起一个ID,方便在报告中识别 @pytest.mark.parametrize( "a, b, expected_sum", [ pytest.param(1, 2, 3, id="positive_nums"), pytest.param(-1, -2, -3, id="negative_nums"), pytest.param(-1, 1, 0, id="mixed_nums"), pytest.param(0, 0, 0, id="zeros") ] ) def test_addition(a, b, expected_sum): assert a + b == expected_sum 运行: pytest test_parametrize_examples.py -v 你会看到 test_is_palindrome_various_inputs 为每一组参数都运行了一次。如果其中一组失败,报告会明确指出是哪一组参数导致了失败。test_addition 的输出会使用你提供的 id 来标识每个测试用例。 参数化的好处: 代码简洁: 避免了为每个场景编写单独的测试函数。 可读性高: 测试数据和预期结果清晰地组织在一起。 易于扩展: 添加新的测试场景只需要在参数列表中增加一行。 覆盖更全: 方便测试各种边界条件和特殊情况。 Fixtures (测试固件/夹具) - 优雅的测试准备与清理 Fixtures 是 pytest 中一个非常强大和核心的概念。它们用于: 提供测试所需的上下文或数据: 比如一个数据库连接、一个临时文件、一个已登录的用户对象等。 管理测试的准备 (setup) 和清理 (teardown) 过程: 确保测试在一致的环境中运行,并在测试结束后释放资源。 你可以把 fixture 想象成戏剧表演中的“道具”或“场景布置”。每个需要特定道具的“场景”(测试函数)都可以声明它需要哪些道具,pytest 会在场景开始前准备好这些道具,并在场景结束后清理它们。 定义 Fixture: Fixture 本身也是一个 Python 函数,使用 @pytest.fixture 装饰器来标记。 使用 Fixture: 测试函数如果需要某个 fixture,只需将其名称作为参数声明即可。pytest 会自动查找并执行对应的 fixture 函数,并将其返回值(如果有的话)传递给测试函数。 1. 基础 Fixture 示例 让我们创建一个 test_fixtures_basic.py 文件: # test_fixtures_basic.py import pytest import tempfile # 用于创建临时文件/目录 import os import shutil # 用于删除目录 # 定义一个 fixture,它会创建一个简单的字典数据 @pytest.fixture def sample_user_data(): print("\n(Fixture: Creating sample_user_data...)") # 方便观察fixture何时执行 data = {"username": "testuser", "email": "test@example.com", "is_active": True} return data # 测试函数使用这个 fixture def test_user_username(sample_user_data): print("\n(Test: Running test_user_username...)") assert sample_user_data["username"] == "testuser" def test_user_is_active(sample_user_data): print("\n(Test: Running test_user_is_active...)") assert sample_user_data["is_active"] is True # 另一个 fixture,演示 setup 和 teardown (使用 yield) @pytest.fixture def managed_tmp_dir(): dir_name = tempfile.mkdtemp(prefix="pytest_managed_") # Setup: 创建临时目录 print(f"\n(Fixture: Created temp directory: {dir_name})") yield dir_name # fixture 的值在这里提供给测试函数 # Teardown: 测试函数执行完毕后,这里的代码会执行 print(f"\n(Fixture: Cleaning up temp directory: {dir_name})") shutil.rmtree(dir_name) # 清理临时目录 def test_create_file_in_managed_dir(managed_tmp_dir): print(f"\n(Test: Running test_create_file_in_managed_dir with {managed_tmp_dir})") file_path = os.path.join(managed_tmp_dir, "test_file.txt") with open(file_path, "w") as f: f.write("Hello from fixture test!") assert os.path.exists(file_path) 运行 pytest -v -s test_fixtures_basic.py ( -s 选项可以让你看到 print 语句的输出,方便观察 fixture 的执行流程)。 你会注意到: sample_user_data fixture 在每个需要它的测试函数(test_user_username 和 test_user_is_active)运行之前都会被调用一次。 managed_tmp_dir fixture 在 test_create_file_in_managed_dir 运行前创建了目录,测试结束后该目录被清理。yield 语句是实现这种 setup/teardown 模式的关键。在 yield 之前是 setup 代码,之后是 teardown 代码。 2. Fixture 作用域 (Scope) Fixture 可以有不同的作用域,决定了 fixture 函数执行的频率以及其返回值的生命周期: function (默认): 每个测试函数执行一次。这是最常见的,确保每个测试都有一个干净、独立的 fixture 实例。 class: 每个测试类执行一次。该类中所有测试方法共享同一个 fixture 实例。 module: 每个模块(测试文件)执行一次。该模块中所有测试函数/方法共享同一个 fixture 实例。 session: 整个测试会话(即一次 pytest 运行)执行一次。所有测试共享同一个 fixture 实例。这对于昂贵的 setup 操作(如启动一个外部服务)非常有用。 通过在 @pytest.fixture 装饰器中指定 scope 参数来设置作用域: # test_fixture_scopes.py import pytest # Session-scoped fixture: 在整个测试会话中只执行一次 @pytest.fixture(scope="session") def db_connection(): print("\n(SESSION Fixture: Connecting to database...)") connection = "fake_db_connection_string" # 模拟数据库连接 yield connection print("\n(SESSION Fixture: Closing database connection...)") # Module-scoped fixture: 在这个模块中只执行一次 @pytest.fixture(scope="module") def module_resource(db_connection): # Fixtures 可以依赖其他 fixtures print(f"\n(MODULE Fixture: Setting up module resource using {db_connection}...)") resource = {"id": "module_res_123", "db": db_connection} yield resource print("\n(MODULE Fixture: Tearing down module resource...)") class TestUserOperations: # Class-scoped fixture: 对这个类只执行一次 @pytest.fixture(scope="class") def user_service(self, module_resource): # 注意类方法中的 fixture 需要 self print(f"\n(CLASS Fixture: Initializing UserSerice with {module_resource['id']}...)") service = f"UserService_instance_for_{module_resource['id']}" yield service print("\n(CLASS Fixture: Shutting down UserService...)") # Function-scoped fixture (默认) @pytest.fixture def new_user_payload(self): print("\n(FUNCTION Fixture: Creating new_user_payload...)") return {"username": "temp_user", "role": "guest"} def test_get_user(self, user_service, db_connection): # 使用 class 和 session fixture print(f"\n(Test: test_get_user using {user_service} and {db_connection})") assert user_service is not None assert "fake_db" in db_connection def test_create_user(self, user_service, new_user_payload, module_resource): # 使用 class, function, module fixture print(f"\n(Test: test_create_user using {user_service}, payload: {new_user_payload}, module_res: {module_resource['id']})") assert new_user_payload["username"] == "temp_user" assert module_resource is not None def test_another_module_level_test(module_resource, db_connection): print(f"\n(Test: test_another_module_level_test using {module_resource['id']} and {db_connection})") assert "module_res" in module_resource["id"] 运行 pytest -v -s test_fixture_scopes.py。仔细观察 print 语句的输出顺序和次数,你就能理解不同作用域的 fixture 是如何工作的。 选择合适的作用域很重要: 如果 fixture 的创建和销毁成本很高,或者你希望在多个测试之间共享状态(要小心!),可以使用更广的作用域(class, module, session)。 为了测试的独立性和避免副作用,function 作用域通常是首选。 3. 内置 Fixtures pytest 提供了一些非常有用的内置 fixtures,例如: tmp_path (function scope): 提供一个临时的目录路径 (pathlib.Path 对象),测试结束后会自动清理。 tmp_path_factory (session scope): 一个工厂 fixture,可以用来创建多个临时目录。 capsys, capfd: 用于捕获测试期间打印到 stdout/stderr 的内容。 monkeypatch: 用于安全地修改或替换模块、类或对象的属性,测试结束后自动恢复。 request: 一个特殊的 fixture,提供了关于当前正在执行的测试请求的信息。 你在之前的教程中已经用到了 tmp_path: # test_fixture.py (部分回顾) @pytest.fixture def tmp_file(tmp_path): # tmp_path 是内置 fixture file_path = tmp_path / "my_temp_file.txt" file_path.write_text("test content") return file_path 4. conftest.py: 共享 Fixtures 如果你的多个测试文件都需要使用相同的 fixtures,你可以将它们定义在一个名为 conftest.py 的文件中。pytest 会自动发现并加载 conftest.py 文件中的 fixtures,使其在同一目录及其子目录下的所有测试文件中可用,无需显式导入。 项目结构示例: my_project/ ├── conftest.py # 共享的 fixtures 在这里定义 ├── package_a/ │ └── test_module_a.py └── package_b/ └── test_module_b.py ```conftest.py` 中的内容: ```python # my_project/conftest.py import pytest @pytest.fixture(scope="session") def global_config(): print("\n(CONFTEST: Loading global config...)") return {"api_url": "http://example.com/api", "timeout": 30} 在 test_module_a.py 中可以直接使用 global_config: # my_project/package_a/test_module_a.py def test_api_url(global_config): # 无需导入,可以直接使用 assert "example.com" in global_config["api_url"] ```conftest.py` 是组织和共享 fixtures 的标准方式,能让你的测试代码更整洁。 ## 使用标记 (Markers) 管理测试 `pytest` 允许你使用“标记 (markers)”来给测试函数或类添加元数据。这些标记可以用于: * 跳过某些测试。 * 在特定条件下跳过测试。 * 将测试标记为预期失败 (xfail)。 * 对测试进行分类,方便选择性地运行。 ### 1. 内置标记 * **`@pytest.mark.skip(reason="...")`**: 无条件跳过该测试。 * **`@pytest.mark.skipif(condition, reason="...")`**: 当 `condition` 为真时跳过该测试。 * **`@pytest.mark.xfail(condition, reason="...", strict=False)`**: 标记测试为“预期失败”。如果测试实际通过了(而你标记为 xfail),默认情况下会报告为 `XPASS`。如果测试如预期般失败了,会报告为 `XFAIL`。如果设置 `strict=True`,那么 `XPASS` 会被视为测试失败。这对于标记那些已知有 bug 但暂时不修复的测试很有用。 * **`@pytest.mark.parametrize(...)`**: 我们已经学习过了,用于参数化测试。 ```python # test_markers.py import pytest import sys def get_python_version(): return sys.version_info @pytest.mark.skip(reason="这个功能尚未实现") def test_new_feature(): assert False IS_WINDOWS = sys.platform == "win32" @pytest.mark.skipif(IS_WINDOWS, reason="此测试仅在非 Windows 系统上运行") def test_linux_specific_path(): path = "/usr/local/bin" assert path.startswith("/") @pytest.mark.skipif(get_python_version() < (3, 8), reason="需要 Python 3.8 或更高版本") def test_feature_for_python38_plus(): # 一些只在 Python 3.8+ 中可用的特性 assert True @pytest.mark.xfail(reason="已知bug #123,除数为零") def test_division_bug(): assert 1 / 0 == 1 # 这会抛出 ZeroDivisionError @pytest.mark.xfail(get_python_version() < (3, 10), reason="此功能在旧版Python中可能表现不同") def test_potentially_flaky_on_old_python(): # 假设这个测试在 Python < 3.10 时可能通过也可能失败 if get_python_version() < (3, 10): assert 1 == 1 # 在旧版 Python 中,我们预期它可能失败 (xfail) else: assert 1 == 1 # 在新版 Python 中,我们预期它通过 2. 自定义标记与运行特定标记的测试 你可以定义自己的标记,以便对测试进行逻辑分组。在 pytest.ini 或 pyproject.toml 文件中注册自定义标记是个好习惯,以避免拼写错误和警告。 pytest.ini 示例: [pytest] markers = slow: 标记运行缓慢的测试 smoke: 标记为冒烟测试,用于快速检查核心功能 integration: 标记为集成测试 在测试中使用自定义标记: # test_custom_markers.py import pytest import time @pytest.mark.slow def test_very_slow_operation(): time.sleep(2) # 模拟一个耗时操作 assert True @pytest.mark.smoke def test_quick_check(): assert 1 + 1 == 2 @pytest.mark.integration @pytest.mark.smoke # 一个测试可以有多个标记 def test_api_login(): # 模拟 API 登录 assert True 运行特定标记的测试: 使用 -m 命令行选项: pytest -m smoke # 只运行标记为 smoke 的测试 pytest -m "not slow" # 运行所有未标记为 slow 的测试 pytest -m "smoke and integration" # 运行同时标记为 smoke 和 integration 的测试 pytest -m "smoke or slow" # 运行标记为 smoke 或 slow 的测试 组织测试:测试类 虽然 pytest 不需要你把测试写在类里,但对于组织一组相关的测试,使用类是一个不错的选择。 类名必须以 Test 开头。 类中的测试方法名必须以 test_ 开头。 不需要继承任何特定的基类 (如 unittest.TestCase)。 # test_calculator_class.py class Calculator: def add(self, a, b): return a + b def subtract(self, a, b): return a - b def multiply(self, a, b): return a * b def divide(self, a, b): if b == 0: raise ValueError("Cannot divide by zero") return a / b class TestCalculator: # 你可以在类级别使用 fixture,它会对该类的所有测试方法生效 # (如果 fixture scope 是 'class' 或更广) # 例如,可以在这里创建一个 Calculator 实例供所有测试使用 def test_addition(self): # 注意方法需要 self 参数 calc = Calculator() assert calc.add(2, 3) == 5 assert calc.add(-1, 1) == 0 def test_subtraction(self): calc = Calculator() assert calc.subtract(5, 3) == 2 # ... 其他测试方法 ... 配置文件 (pytest.ini 或 pyproject.toml) 你可以通过在项目根目录创建 pytest.ini 文件或在 pyproject.toml 中添加 [tool.pytest.ini_options] 部分,来自定义 pytest 的行为。 pytest.ini 示例: [pytest] # 改变测试文件的发现模式 python_files = test_*.py check_*.py example_*.py # 改变测试函数/方法的发现模式 python_functions = test_* check_* example_* # 改变测试类的发现模式 python_classes = Test* Check* Example* # 默认添加的命令行选项 addopts = -v --cov=. --cov-report=html # 注册自定义标记 (避免警告) markers = slow: marks tests as slow to run serial: marks tests that cannot be run in parallel # 忽略某些目录 norecursedirs = .git venv build *.egg-info 这只是冰山一角,pytest 的配置选项非常丰富。 总结与后续学习 恭喜你!通过这个扩展教程,你已经掌握了 pytest 的许多核心概念和实用技巧: 编写和运行基础测试。 理解不同的输出模式 (-v, -q)。 使用强大的 assert 语句进行断言和异常测试。 通过 @pytest.mark.parametrize 实现参数化测试,提高测试覆盖率和代码复用。 掌握了 Fixture 的核心用法,包括定义、使用、作用域 (function, class, module, session)、带 yield 的 setup/teardown 模式,以及如何通过 conftest.py 共享 fixtures。 了解了如何使用标记 (@pytest.mark.*) 来管理和选择性地运行测试。 知道了如何将测试组织在类中。 对 pytest 的配置文件有了初步认识。 接下来你可以探索: 更高级的 Fixture 用法: 如 autouse fixtures,fixture 的参数化,使用 fixture 返回工厂函数等。 插件的使用: pytest-cov: 测试覆盖率。 pytest-xdist: 并行测试。 pytest-mock: 方便地使用 mocking。 针对你使用的框架(如 Django, Flask, FastAPI)的 pytest 插件。 生成 HTML 测试报告: 使用 pytest-html 插件。 pytest 官方文档: 这是最权威和最全面的学习资源 (https://docs.pytest.org/)。 编写测试是保证代码质量、提升开发信心的关键环节。pytest 以其简洁和强大,让编写测试不再是一件苦差事,反而可以成为一种乐趣。希望这篇教程能帮助你轻松入门并爱上 pytest!
Techniques
· 2025-10-08
【笔记整理|2024年上半年】Python开发环境与工程化笔记整理
【笔记整理|2024年上半年】Python开发环境与工程化笔记整理 本文汇总了Python开发环境配置、性能优化、Web开发和工程化实践的技术要点,为高效开发提供全面指导。 Conda环境管理 环境配置 初始化设置 # Conda初始化脚本 __conda_setup="$('/home/user/miniconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)" eval "$__conda_setup" if [ -f "/home/user/miniconda3/etc/profile.d/conda.sh" ]; then . "/home/user/miniconda3/etc/profile.d/conda.sh" else export PATH="$PATH:/home/user/miniconda3/bin" fi unset __conda_setup 环境迁移和重建 从旧miniconda迁移到新anaconda时的常见问题: InvalidArchiveError错误: # 清理conda缓存解决依赖问题 conda clean -a 包冲突解决策略: # 例如:acpype依赖AmberTools但Amber不包含acpype # 通过conda安装会获取另一个ambertools # 解决方案:在base环境中使用pip安装 pip install acpype 配置文件设置 conda config --file .condarc --add pkgs_dirs 环境变量配置 # Python环境路径示例 previous_path = "/home/user/anaconda3/envs/pmx/lib/python3.10/site-packages/pmx/data/mutff" # Boost库路径示例(用于编译) boost_path = "/home/user/anaconda3/envs/AMBER22/lib/cmake/Boost-1.78.0/BoostConfig.cmake" 包管理最佳实践 PyPI镜像配置 # 临时使用镜像 pip install -i https://mirrors.zju.edu.cn/pypi/web/simple some-package # 永久配置镜像 pip config set global.index-url https://mirrors.zju.edu.cn/pypi/web/simple 包强制重装 pip install --upgrade --force-reinstall <package> Web开发与爬虫技术 Selenium自动化 Selenium基础设置 from selenium import webdriver # 创建WebDriver实例 driver = webdriver.Chrome() 连接错误处理 urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=17823): Max retries exceeded with url: /session/xxx/url 这种错误通常是由于目标计算机积极拒绝连接导致的。 页面滚动与交互 页面滚动实现 # 方法1:JavaScript执行滚动 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 方法2:发送按键模拟用户滚动 from selenium.webdriver.common.keys import Keys driver.find_element_by_tag_name('body').send_keys(Keys.PAGE_DOWN) 元素交互异常 ElementNotInteractableException 此异常表示要交互的元素不在允许交互的状态。可能原因: 元素被隐藏 元素被其他元素覆盖 元素尚未加载完成 静态vs动态内容抓取 静态网页数据抓取 可以使用requests库结合BeautifulSoup来检索静态网页数据。但如果目标网页使用JavaScript动态加载内容,requests可能无法获取完整的页面内容,这种情况下Selenium更适合。 动态加载内容识别 如果div元素通过JavaScript动态加载,使用requests库可能无法获取到这些内容,因为requests只能获取初始的静态HTML,不会执行JavaScript。 工具选择建议 Beautiful Soup:适合解析静态HTML/XML内容,速度更快 Selenium:主要用于动态网页交互和浏览器自动化 Cython性能优化 Cython编译与使用 Cython编译命令 python setup.py build_ext Cython使用建议 可以考虑使用Cython优化一些简单的Python项目。但在非常复杂的场景下,某些语法特性不支持,可能会有绕不过去的坑。 跨平台编译 Windows和Linux需要分别执行编译,然后将编译结果拷贝到目标环境。 数据处理与文件操作 字符串处理技巧 bytes字符串替换 # 在bytes字符串中替换子串 byte_string = byte_string.replace(b"<br/>", b"\n\n") 数字字符串判断 s1 = "12345" # 使用内置方法判断字符串是否为数字 s1.isdigit() # 判断是否为数字 s1.isnumeric() # 判断是否为数值 CSV文件处理 CSV文件写入 import csv # 使用Python标准库csv模块写入CSV文件 with open('output.csv', 'w', newline='') as csvfile: writer = csv.writer(csvfile) writer.writerow(['列1', '列2', '列3']) writer.writerow(['数据1', '数据2', '数据3']) 文件移动操作 Python文件移动教程:https://www.learndatasci.com/solutions/python-move-file/ Python语言特性 条件表达式 Python没有直接的问号语句(如C语言中的 condition ? expression1 : expression2),但有等价的条件表达式 result = value1 if condition else value2 # 这等价于其他语言中的三元条件运算符 外部程序调用 import subprocess # 在Python中调用外部程序(如antechamber) def call_antechamber(input_file, output_file): cmd = f"antechamber -i {input_file} -o {output_file}" result = subprocess.run(cmd, shell=True, capture_output=True, text=True) return result 退出函数使用 exit函数错误 # 错误:NameError: name 'exit' is not defined exit() # 正确:需要导入sys模块 import sys sys.exit() 作用域问题 仅导入sys模块不足以使exit进入全局作用域,需要明确使用sys.exit()。 JSON数据处理 import json # 加载JSON数据的标准方法 with open('data.json', 'r') as f: data = json.load(f) 环境配置优化 PATH环境变量清理 # 清理重复的PATH条目 export PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!($0 in a) {a[$0]; print}' | sed 's/:$//') 子进程配置 # subprocess.Popen默认使用/bin/sh # 若要使用bash需要设置executable参数 subprocess.Popen(..., executable='/bin/bash') Python subprocess使用bash:https://www.saltycrane.com/blog/2011/04/how-use-bash-shell-python-subprocess-instead-binsh/ 代理配置 # 设置HTTP代理 export http_proxy="http://127.0.0.1:7890" 开发工具集成 Python外部程序调用 import subprocess # 调用外部程序的标准方法 def run_external_command(command): result = subprocess.run(command, shell=True, capture_output=True, text=True) return result.stdout, result.stderr 包管理集成 使用subprocess调用系统包管理器: # 调用antechamber等外部工具 def call_antechamber(input_file, output_file): cmd = f"antechamber -i {input_file} -o {output_file}" result = subprocess.run(cmd, shell=True, capture_output=True, text=True) return result PyCharm环境问题: PyCharm本身是一个代码编辑器(IDE),而不是一个网页浏览器。所以它不能像Chrome或Edge那样直接”打开”并渲染localhost:8501的页面内容。建议端口转发。 相关学习资源 Python打包 科学Python打包指南:https://learn.scientific-python.org/development/guides/packaging-simple/ 故障排除与最佳实践 常见错误模式 环境冲突:不同conda环境中包版本不兼容 连接错误:Web爬虫中的网络连接问题 编译问题:Cython跨平台编译差异 字符编码:bytes和str处理不当 调试建议 隔离测试环境冲突 使用虚拟环境避免依赖污染 记录完整的编译配置 注意跨平台兼容性问题 开发环境检查清单 Python版本:确保版本兼容性 依赖管理:使用requirements.txt或environment.yml 虚拟环境:为每个项目创建独立环境 代码质量:使用linter和formatter工具 性能监控:定期进行性能分析 本文基于2023年9月至2024年上半年的开发实践整理,涵盖Python工程化和开发环境配置的实用技术要点
Techniques
· 2025-10-08
【笔记整理|2024年上半年】Python数据分析与可视化技术指南
【笔记整理|2024年上半年】Python数据分析与可视化技术指南 本文汇总了在科研数据分析中使用Python的实用技巧,涵盖数据处理、可视化、性能分析等核心技术。 NumPy和SciPy数据处理 数组操作和统计分析 寻找数组中的局部极值 使用scipy.signal.argrelextrema函数寻找一维数组中的相对极值(最大值和最小值): import numpy as np from scipy.signal import argrelextrema from scipy.stats import gaussian_kde # 示例:寻找密度函数的局部最小值 data = np.array([...]) # 你的数据 density = gaussian_kde(data) x = np.linspace(data.min(), data.max(), 1000) y = density(x) # 寻找局部最小值 minima_indices = argrelextrema(y, np.less) minima = x[minima_indices] 注意:argrelextrema函数寻找y是局部最小值的索引(即小于其邻居的点)。 数组处理常见问题 # 处理数组转换失败的问题 # "cannot process into arrays" 错误通常是由于数据类型不一致 try: arr1 = np.array(str1.split()) result = np.array([float(x) for x in arr1]) except ValueError as e: print(f"Array conversion failed: {e}") 数据可视化 Matplotlib配置和使用 基础导入和配置 import matplotlib.pyplot as plt import matplotlib # 获取matplotlib缓存目录 cache_dir = matplotlib.get_cachedir() print(f"Matplotlib cache directory: {cache_dir}") 字体和缓存问题解决 import os import matplotlib # 清理matplotlib字体缓存 font_directory = os.path.join(matplotlib.get_data_path(), 'fonts', 'ttf') # 如果遇到字体问题,删除缓存重新生成 # rm -r /home/username/.cache/matplotlib Seaborn可视化技巧 Violin Plot使用和问题解决 import seaborn as sns import matplotlib.pyplot as plt # 创建violin plot sns.violinplot(data=data) # 常见问题:分布显示为负值(但数据全为正) # 解决方案:使用内核密度估计的截断参数 sns.violinplot(data=data, cut=0) # cut=0避免扩展到数据范围之外 问题说明:使用sns.violinplot时发现某些分布低于0,但数据全为正值。这是因为核密度估计默认会在数据范围外进行插值。 Violin Plot进阶用法 Violin Plot数据分析指南:https://www.geeksforgeeks.org/violin-plot-for-data-analysis/ 分组柱状图制作 多种方法实现分组柱状图 当数据格式为矩阵时,创建分组柱状图的5种方法: import matplotlib.pyplot as plt import numpy as np import pandas as pd # 方法1:使用matplotlib def method1_matplotlib(data_matrix): x = np.arange(len(data_matrix)) width = 0.35 fig, ax = plt.subplots() for i in range(data_matrix.shape[1]): ax.bar(x + i*width, data_matrix[:, i], width, label=f'Group {i+1}') ax.legend() # 方法2:使用pandas def method2_pandas(data_matrix): df = pd.DataFrame(data_matrix) df.plot(kind='bar', ax=plt.gca()) # 方法3:使用seaborn def method3_seaborn(data_matrix): df = pd.DataFrame(data_matrix) df_melted = df.melt() sns.barplot(data=df_melted, x='variable', y='value') # 其他方法可参考plotnine等工具 Pandas数据操作 基础数据处理 import pandas as pd # 基本数据导入和处理 df = pd.read_csv('data.csv') 数据结构操作 字典排序 # 按键对字典进行排序 mydict = {'c': 3, 'a': 1, 'b': 2} sorted_mydict = dict(sorted(mydict.items(), key=lambda item: item[0])) Python字典排序指南:https://www.golinuxcloud.com/python-sort-dictionary-by-key/ 性能分析与优化 代码性能分析 cProfile性能分析 在Python中,可以使用cProfile模块来分析每个函数的执行时间: import cProfile cProfile.run('your_function()') 不同运行环境性能对比 实际测试发现: PyCharm profile:71秒 简单debug模式:56秒 命令行直接运行:31秒 性能分析显示主要耗时操作: fit操作:约8秒 concat操作:6秒 process_dict:11.6秒 算法复杂度理解 Python排序算法 Python内置的sorted()函数使用双轴快排算法(timsort),时间复杂度: 最坏情况:O(n * log n) 平均情况:O(n * log n) W3Schools Python sorted()函数:https://www.w3schools.com/python/ref_func_sorted.asp 哈希表查找效率 集合和字典在Python中都通过哈希表实现,元素查找时间复杂度通常为O(1),这使得元素位置可以快速定位。 高阶函数与函数式编程 函数套用(高阶函数) 在Python中,函数可以套用函数,这是一种常见的编程模式,也被称为高阶函数。这意味着一个函数可以接受另一个函数作为参数,或者返回一个函数作为结果。 动态属性设置 # 使用setattr动态设置对象属性 setattr(obj, 'attribute_name', value) # __getattr__方法在访问不存在的属性时被调用 def __getattr__(self, name): # 处理不存在的属性访问 pass 图论和网络分析 节点连接分析 处理图中节点组之间的连接问题: # 问题:找到连接两个节点组的节点对 # 可能每个节点组对有一个节点对连接 # 解决思路:构建二分图可能有助于快速找到这些连接 def find_connecting_pairs(graph, group1, group2): """ 找到连接两个节点组的节点对 考虑使用二分图表示来优化搜索 """ connecting_pairs = [] for node1 in group1: for node2 in group2: if graph.has_edge(node1, node2): connecting_pairs.append((node1, node2)) return connecting_pairs 列表元素计数 # 统计列表中元素出现次数的多种方法 from collections import Counter # 方法1:使用Counter my_list = [1, 2, 2, 3, 3, 3] counts = Counter(my_list) Python列表元素计数方法:https://datagy.io/python-count-occurrences-in-list/ 组合与迭代 列表组合生成 import itertools # 获取两个列表的所有唯一组合 combinations = list(itertools.product(list1, list2)) Python组合生成教程:https://www.geeksforgeeks.org/python-program-to-get-all-unique-combinations-of-two-lists/ 迭代中修改集合 # 错误示例:迭代过程中修改集合大小 RuntimeError: Set changed size during iteration 避免在迭代过程中修改正在迭代的集合。 科研数据处理最佳实践 数据验证 def validate_data(data): """验证科研数据的基本检查""" # 检查数据范围合理性 if np.any(data < 0) and data_should_be_positive: print("Warning: Found negative values in positive-only data") # 检查缺失值 if np.any(np.isnan(data)): print("Warning: Found NaN values") # 检查异常值 q1, q3 = np.percentile(data, [25, 75]) iqr = q3 - q1 outliers = (data < q1 - 1.5*iqr) | (data > q3 + 1.5*iqr) if np.any(outliers): print(f"Warning: Found {np.sum(outliers)} potential outliers") 可重现性保证 # 设置随机种子确保结果可重现 np.random.seed(42) # 保存分析环境信息 def save_environment_info(): import sys import numpy import matplotlib import pandas env_info = { 'python_version': sys.version, 'numpy_version': numpy.__version__, 'matplotlib_version': matplotlib.__version__, 'pandas_version': pandas.__version__ } return env_info 大数据处理 # 处理大型数组时的内存优化 def process_large_array(data, chunk_size=1000): """分块处理大型数组""" results = [] for i in range(0, len(data), chunk_size): chunk = data[i:i+chunk_size] processed_chunk = process_chunk(chunk) results.append(processed_chunk) return np.concatenate(results) 向量化计算 # 优先使用NumPy向量化操作而非Python循环 # 低效方式 def slow_calculation(data): results = [] for x in data: results.append(x**2 + 2*x + 1) return results # 高效方式 def fast_calculation(data): return data**2 + 2*data + 1 第三方库和工具 Plotnine使用 # plotnine相关问题和解决方案 Plotnine GitHub问题:https://github.com/has2k1/plotnine/issues/79 plotnine是Python中ggplot2的实现,适合熟悉R语法的用户。 调试和故障排除 常见错误模式 数组转换失败:通常由数据类型不一致造成 可视化异常值:密度估计超出数据范围 内存不足:大数据集处理时的常见问题 迭代修改错误:在迭代过程中修改集合 调试建议 使用print()语句检查中间结果 利用Jupyter notebook的交互式特性 保存关键步骤的中间数据 记录完整的软件环境信息 本文基于2023年9月至2024年上半年的技术实践整理,涵盖Python数据分析和可视化的核心技术要点
Techniques
· 2025-10-07
<
>
Touch background to close