比技术更难进化的,是人的思维方式

每一段职场故事,都是一面镜子。有人走在前面,有人停在原地,但真正值得敬佩的,往往是那些能够不断进化的人。

曾经,有这样一位技术伙伴。他在一家公司独当一面,凭着过硬的动手能力和坚持不懈的努力,独立搭建起了一套完整且实用的系统。从第一行代码到第一版上线,以及后面的持续迭代工作,他几乎亲历亲为,夜以继日,撑起了一片属于自己的天地,为公司的业务也做到了雪中送炭。

在很长一段时间里,他被视为团队的支柱。后面来了几位新人,他们也怀着敬意向他学习,他的经验成为解决问题的重要凭借,他的方案成为评估技术选型的模板。那段日子,他像一位孤独的工匠,在属于自己的城堡里,雕刻着精致而独特的艺术品。

但时代不会停下来等任何一个人。

后来,随着团队不断扩张,越来越多的社招与校招的新同事加入。他们有着完全不一样的科研和工作背景,他们为团队带来了新的力量、新的想法、新的工具、新的模式。新的风在逐渐吹拂进来,对团队而言带着未知的机会,也带着隐隐的不安。

当有新的同事提出换一种更高效的方式来管理数据,他皱了皱眉头;当有人建议重新设计系统架构以支持未来更大规模的扩展,他下意识地进行反驳;当有人分享外部更先进的工具链时,他则质疑其开源的使用范围、安全性与可控性,并会说“没想到外部的工具竟然那么 low”。渐渐地,他和新同事们之间的讨论不再是协作,而是争论,甚至演变成了角力。

他想尽一切办法守护着自己曾经创造的成果,维护着自己创造的技术栈,就像守护一座渐渐老去的城池。

这段故事里,没有真正的对与错。只是,它让人深刻意识到:比代码更难维护的,是人的认知系统;比技术更容易过时的,是人的思维方式。

所有曾经的光荣和努力,都值得尊重。但如果一个人始终以“我做过”来定义自己的价值,很容易在变化面前筑起一道又一道无形的高墙。时间久了,高墙之内,是自我保护,也是自我设限。

成长,不是抵抗变化,而是接纳变化,驾驭变化。

很多时候,我们以为自己是在守护成果,其实不过是在固守过往的安全感。对变化的排斥,不一定源自傲慢,更多时候,源自恐惧——害怕自己的价值被动摇,害怕新的世界自己跟不上,害怕多年积累的一切被证明“不再先进”,害怕自己不再是团队唯一的核心力量。

于是,怀疑代替了好奇,防御取代了探索,争论遮蔽了倾听。

我们常常低估了自己对稳定的依赖,也低估了世界变化的速度。
技术在飞奔,行业在更迭,每一个曾经自豪的“我做过”,如果无法继续演变成“我们一起做得更好”,就会在不知不觉中,被时代轻轻擦肩而过。真正的危机,并不是新技术到来,也不是新同事提出了不同的方案。真正的危机,是当我们面对变化时,心中只剩下防备和抵触,而没有了好奇与学习的冲动。

思维停滞,比技术落后更可怕。
认知固化,比工具过时更致命。

而且,一个人如果长时间沉浸在“我是功臣”的自我叙事里,就很容易走向两个极端:

  1. 一是,把团队视作威胁,拒绝与其他同事进行分享和共建;
  2. 二是,把规范与体系视作束缚,维护自己开发的所有内容,只愿做自己的孤岛。

但真正长远的事业,真正了不起的团队,永远是靠不断引入新力量,不断自我更新,才能生生不息。有时候,旧有的功臣确实需要做出让步。但这种让步,不是丢掉了自己的价值,而是把自己的价值,升华到了成就更大的整体之中。

反过来说,作为新加入的人,我们也应该有足够的耐心和尊重。理解曾经构建体系的人并不容易,尊重他们的经验和贡献,用行动而不是语言赢得信任,用协作而不是颠覆建立连接。

成长,从来不只是单向的要求。不仅要求自己打开心扉,也要求自己包容别人;既要有挑战旧世界的勇气,也要有修复彼此信任的耐性。

所以,从今天开始,我们可以问问自己:

  • 我是不是还在用“我做过”的故事,替代“我还能做得更好”的探索?
  • 我是不是已经开始本能地抗拒新鲜的事物?
  • 我是不是因为害怕失去过去的成就感,而放弃了拥抱新的成长?

如果答案是肯定的,请不要自责。成长,从来不是一蹴而就的觉醒,而是一次次微小但坚定的自我修正。真正成熟的人,不是守着旧地图固步自封的人,而是能在风起云涌中,不断校准航向,继续出发的人。

愿我们以此为镜:

  • 开放代替封闭,像海绵一样,吸收新的技术、新的思路;
  • 谦虚战胜傲慢,承认世界之大,技术之广,永远有人值得学习;
  • 长期主义压倒短期功利,把眼光放远,把心气放平,把每一次小小的进步积累成未来的跃迁。

别让一时的成就,变成了自我封闭的借口。别让一段历史的光环,变成了前行路上的绊脚石。真正了不起的人,不是站在过去荣誉里的人,而是能在每一次技术更迭、每一次认知崩塌后,依然选择重新学习、重新奔跑的人。要记住:

最值得骄傲的,不是你写过的某一段代码,而是你不断修复、不断优化、不断重构的人生本身。

未来属于那些不断进化的人,愿你我都是那个可以持续升级的自己。

Python代码检测工具

代码规范

对于程序员而言,代码规范不仅仅是为了让代码看起来更整洁,它直接影响着代码的可读性、可维护性和团队的协作效率。统一的代码风格使得团队成员能够快速理解彼此的代码,无论是在日常的开发、代码审查还是修复bug时,都能有效避免因风格差异带来的误解或错误。遵循代码规范还能帮助提高代码质量,降低潜在的bug风险,并且对后期的扩展与重构更加友好。尤其是在大型项目或多团队协作的情况下,良好的代码规范更是保证项目可持续发展的基石。因此,始终坚持良好的代码规范是每个开发者应尽的责任,它不仅仅是为了提升个人编程习惯,更是为了整个团队的协同作战与代码的长期健康。

Python代码规范

Python 提倡简洁、清晰、易读的代码风格,PEP 8 是 Python 社区推荐的官方代码风格指南,它帮助开发者统一代码风格,提高代码的可读性和可维护性。遵循 Python 代码规范不仅有助于开发者之间的协作,还能让代码更加规范化,减少潜在的错误。以下是一些常见的 Python 代码规范。

1. 命名规范

  • 变量、函数和方法的命名:使用小写字母,并通过下划线 _ 分隔单词(即蛇形命名法)。例如:user_age,calculate_total()
  • 类名的命名:使用首字母大写的驼峰命名法。例如:UserProfile,OrderProcessor
  • 常量命名:所有字母大写,单词间使用下划线分隔。例如:MAX_RETRIES,PI
  • 私有变量和方法:以单下划线 _ 开头,表示该变量或方法是内部使用,不应直接访问。例如:_internal_data
  • 避免使用Python保留字(如 class、if、try 等)作为变量名。

2. 缩进与空格

  • 缩进:使用 4 个空格进行缩进,不要使用制表符(Tab)。这是 Python 语法要求的,错误的缩进会导致语法错误。
  • 行内空格:在运算符两边加空格,增强可读性。
    例如:对于赋值:x = 10
    对于运算符:y = x + 5
  • 函数参数的空格:函数定义和调用时,参数列表的两边不要加空格。例如:
def add_numbers(a, b):    
    return a + b
  • 括号内的空格:不要在括号内多余的地方加空格。例如:
my_list = [1, 2, 3]  # 正确
my_list = [ 1, 2, 3 ]  # 错误

3. 行长限制

单行长度:每行代码的长度建议不超过 79 个字符。对于文档字符串(docstring)和长注释,推荐不超过 72 个字符。这有助于提高代码的可读性,尤其是在显示设备宽度有限时。如果行长超过限制,可以使用反斜杠 \ 进行换行,或者在括号、列表、字典等容器中自动换行。

4. 文档字符串(Docstring)

模块和类:在模块和类定义后,添加文档字符串说明其功能。文档字符串应该简洁明了,并且应说明类和模块的主要功能和用途。

class Calculator:    
    """This class performs basic arithmetic operations."""    
    pass
  • 函数和方法:为每个函数和方法提供文档字符串,描述其作用、参数和返回值。
def add(a, b):
    """
    Add two numbers and return the result.
    
    Parameters:
    a (int or float): The first number.
    b (int or float): The second number.
    
    Returns:
    int or float: The sum of a and b.
    """
    return a + b

5. 异常处理

异常捕获:应该尽量避免使用过于宽泛的 except 块,避免捕获不必要的异常。应当明确捕获特定异常。

try:
    x = 1 / 0
except ZeroDivisionError as e:
    print(f"Error: {e}")

多个异常捕获:如果需要捕获多种异常,可以使用元组来列出这些异常类型。

try:
    some_code()
except (TypeError, ValueError) as e:
    print(f"Error: {e}")

6. 导入顺序

标准库导入:首先导入 Python 标准库模块,如 os、sys 等。

第三方库导入:其次导入外部安装的第三方库,例如 numpy、pandas、requests 等。

本地应用库导入:最后导入你自己编写的模块或应用库。

按照以上顺序,导入部分每一类模块之间应该留一行空行。例如:

import os
import sys

import numpy as np
import pandas as pd

from mymodule import my_function

7. 避免重复代码

Python 提供了许多库和工具,可以避免代码重复。如果发现自己写了类似的代码片段多次,应考虑将其提取成函数或类,提升代码的复用性。适当使用 Python 的标准库,如 itertools、functools 等,避免自己手动实现复杂的功能。

遵循 Python 代码规范能够帮助我们编写更简洁、更易于理解和维护的代码。最重要的规范包括命名规则、缩进与空格、行长限制、文档字符串、异常处理等。在大型项目中,团队成员遵循统一的规范可以提高协作效率,减少因代码风格不一致带来的混乱和错误。因此,开发者应该积极遵循 PEP 8 等官方规范,并利用代码规范检查工具(如 flake8、pylint 等)来保持代码质量。

圈复杂度

圈复杂度(Cyclomatic Complexity)是衡量一个程序的控制流复杂度的一个指标,它由 Thomas McCabe 于 1976 年提出。圈复杂度的核心思想是衡量程序中独立路径的数量,反映了程序中控制流的复杂程度。简单来说,圈复杂度可以帮助你了解一个程序有多少条不同的执行路径。

为什么圈复杂度重要?

  • 高圈复杂度:意味着代码中有很多的判断、循环和分支,程序的执行路径复杂。高复杂度的代码难以理解、测试和维护。
  • 低圈复杂度:意味着代码结构简单,控制流清晰,容易理解和维护。

计算圈复杂度

圈复杂度的计算公式为:

V(G)=E−N+2P,其中:

  • V(G) 是圈复杂度(Cyclomatic Complexity)。
  • E 是程序图中的边的数量(边代表程序控制流的转移,比如跳转、条件等)。
  • N 是程序图中的节点的数量(节点代表基本块,即一组顺序执行的语句)。
  • P 是程序图中的连通组件的数量(一般情况下 P = 1,即程序是一个连通的整体)。

具体解释:

E:程序的控制流转移数量。例如,if、while、for、case 语句的数量都会增加边的数量。

N:控制流图中节点的数量,代表代码的块,例如顺序执行的语句组。

P:通常程序只有一个连通组件,即 P = 1,代表程序是一个整体。

直观解释

可以通过 控制流图 来理解圈复杂度。控制流图是一个图论的概念,它将程序的每个基本块(例如条件判断、循环等)表示为图中的节点,程序的控制流(跳转)表示为边。圈复杂度就是计算该图中所有独立路径的数量。

例如,下面是一个简单的代码示例:

def example(a):
    if a > 10:
        return "greater"
    else:
        return "lesser"

这段代码的控制流图非常简单,只有两个分支。它的圈复杂度为 2,因为有两个独立的路径(a > 10 和 a <= 10)。

计算圈复杂度的示例:

  1. 简单顺序执行
def simple_function():
    a = 5
    b = 10
    c = a + b
    return c
  • 控制流图:只有一个顺序的执行,没有条件和分支。
  • 圈复杂度:1(只有一个路径,程序从头到尾顺序执行)
  • 条件判断
def function_with_if(a):
    if a > 10:
        return "greater"
    else:
        return "lesser"

控制流图:有一个 if 语句,形成两个分支路径。圈复杂度:2(一个条件判断,两个路径)

  • 循环语句
def function_with_while(a):
    while a > 0:
        a -= 1
    return a

控制流图:有一个 while 循环,形成一个循环路径。

圈复杂度:2(一个循环结构,两个路径:一个是 while 循环路径,另一个是跳出循环后的路径)

如何使用圈复杂度?

  1. 代码可维护性:高圈复杂度意味着代码结构复杂,容易引入 bug,不利于维护。因此,圈复杂度高的代码通常需要重构。
  2. 测试覆盖率:圈复杂度的一个重要应用是 测试路径覆盖,它提供了最小路径集 的数量,这些路径集需要被单元测试覆盖。如果圈复杂度是 10,那么最少需要设计 10 个不同的测试用例来保证所有路径都被测试。
  3. 代码审查和重构:高圈复杂度通常提示代码不易理解或过于复杂,可能需要重构,降低复杂度,提高可读性。

小结:

  • 低圈复杂度:代码清晰,易于理解和维护,测试更容易覆盖。
  • 高圈复杂度:代码难以理解和测试,容易出错,可能需要重构。

圈复杂度是衡量代码复杂度的重要指标,它能帮助开发者评估代码的质量和可维护性。

Python代码检测工具使用指南

本文介绍多种常用的Python代码检测工具(pylint、flake8、ruff),涵盖安装方法基本使用以及项目级检查的实践指导,帮助开发者快速实现代码质量分析与规范检查。

1. Pylint

1.1 安装

使用pip就可以轻松地把pylint这个工具安装好。

pip install pylint

1.2 使用场景

检查单个文件

pylint my_script.py # 检查单个文件

检查文件夹

pylint src/  # 递归检查目录下所有.py文件

检查项目

pylint project/ --recursive=y # 检查项目

1.3 配置与过滤

生成配置文件:

pylint --generate-rcfile > .pylintrc

如果不想看某类错误的时候,我们可以选择忽略特定错误:

pylint my_script.py --disable=E1101,C0114  # 关闭未解析的属性和缺失docstring警告

2. Flake8

2.1 安装

使用pip就可以轻松地把flake8这个工具安装好。

pip install flake8

2.2 使用场景

检查单个文件

flake8 my_script.py  # 检查单个文件

检查文件夹

flake8 src/  # 检查所有.py文件

检查项目

可以通过下述命令来检查当前的目录和所有子目录

flake8 .  # 递归检查当前目录及子目录

同时,flake8默认会使用pep8第三方包检查代码(经常会安装mccabe和pyflakes,安装之后,flake8就会提供个性的功能)。 pep8第三方包只能检查代码是否符合 pep8 代码规范(所以 flake8默认是使用pep8代码规范做检查)。

相对于Pylint ,flake8提供了些特有的功能。

  • 检查代码的圈复杂度(flake8会调用mccabe计算圈复杂度)。
  • 圈复杂度和if语句有关,选择分支越多,圈复杂度越高。
  • 圈复杂度越低越好。圈复杂度高影响代码可读性,代码容易出错。
  • flake8官网建议圈复杂不要超过 12 。

2.3 配置与扩展

配置文件支持:在 setup.cfg 或 .flake8 中配置规则:

pip install flake8-mutable  # 安装可变默认参数检测插件flake8 --enable-extensions MutableDefaultArg

3. Ruff

3.1 安装

使用pip就可以轻松地把ruff这个工具安装好。

pip install ruff
# 或使用独立二进制(无Python环境依赖):
curl -Ls https://github.com/astral-sh/ruff/releases/latest/download/ruff-linux-amd64 | sudo tee /usr/local/bin/ruff >/dev/null && sudo chmod +x /usr/local/bin/ruff

3.2 使用场景

检查单个文件

ruff check my_script.py

检查文件夹/项目

ruff check src/  # 检查目录ruff check .     # 检查整个项目

自动修复问题

ruff check --fix my_script.py

3.3 配置

兼容flake8配置:直接复用 .flake8 或 pyproject.toml,或在 pyproject.toml 中指定规则:[tool.ruff] line-length = 100 ignore = [“E501”, “F401”]

4.  Mccabe

这是用来检查圈复杂度的工具

4.1 安装

pip install mccabe
pip install --upgrade mccabe
pip uninstall mccabe

4.2 使用场景

python -m mccabe --min 5 mccabe.py
("185:1: 'PathGraphingAstVisitor.visitIf'", 5)
("71:1: 'PathGraph.to_dot'", 5)
("245:1: 'McCabeChecker.run'", 5)
("283:1: 'main'", 7)
("203:1: 'PathGraphingAstVisitor.visitTryExcept'", 5)
("257:1: 'get_code_complexity'", 5)

5.  Prospector

5.1 Prospector项目介绍

Prospector 是一款专为 Python 代码设计的强大分析工具,它旨在提供关于错误、潜在问题、规范违规以及复杂性方面的详尽信息。这款工具集成了诸如 Pylint、pycodestyle 和 McCabe 等众多Python代码分析工具的功能于一身。通过自定义配置文件(即“profile”),Prospector 提供了适用于大多数情况的默认配置,旨在帮助开发者在无需大量前期设置的情况下即可开始提升代码质量。它还能够适应项目所依赖的特定库和框架,比如自动调整对 Django 或 Celery 的支持,以减少误报。

5.2 项目快速启动

要迅速开始使用 Prospector,首先确保你的环境中安装了 Python 和 pip。然后,执行以下命令来安装 Prospector:

pip install prospector

安装完毕后,在你的Python项目根目录下运行 Prospector,即可获取到代码审查报告:

cd /path/to/your/python/projectprospector

这将输出可能存在的问题列表,帮助你识别和修正代码中的隐患。对于更定制化的控制,可以添加额外参数,例如使用 –strictness medium 来设定中等严格的检查级别。

prospector --strictness high

5.3 应用案例和最佳实践

在使用 Prospector 时,一个典型的最佳实践是将其集成到持续集成(CI)流程中。比如,通过 .pre-commit-config.yaml 文件配置预提交钩子,确保每次提交前都经过代码质量检查:

repos:
  - repo: https://github.com/PyCQA/prospector
    rev: 1.10.0  # 使用具体版本或'master'以获取最新版本
    hooks:
      - id: prospector
        args: ["--summary-only"]  # 只显示总结,简化输出

对于团队协作项目,通过创建适合自己团队编码风格的配置文件(prospector.yml),可以进一步优化Prospector的行为,确保所有开发者遵循一致的标准。

5.4 典型生态项目

Prospector 在 Python 生态中扮演着重要角色,尤其是在那些重视代码质量和一致性维护的项目中。结合其他生态项目,如 mypy 进行静态类型检查,或 bandit 进行安全审计,可以构建出更全面的质量保障体系。Prospector的设计使其能与这些工具良好协同工作,通过在Prospector中启用相应插件,可以实现多维度的代码检查。

通过简单的配置和灵活的插件机制,Prospector不仅提升了单个项目的开发效率,也促进了整个Python社区代码标准的一致性和代码质量的普遍提升,成为了现代软件开发生命周期中不可或缺的一部分。

参考资料

  1. 代码检查工具文档介绍:https://wangmeng-python.readthedocs.io/en/latest/readability/code-analysis-tools.html
  2. Mccabe的GitHub链接:https://github.com/pycqa/mccabe
  3. Prospector的GitHub链接:https://github.com/prospector-dev/prospector
  4. ruff:https://myapollo.com.tw/blog/python-linter-ruff/