Python优雅计划(一)

众所周知,从OI赛场里出来的选手总有一些奇奇怪怪的编码习惯,而压行缩减代码量又是其最为广为流传的《恶习》之一,我曾经也是他们的一员;对着执行了十几亿次的GTA代码嗤之以鼻,对着Windows的多年屎山表示不屑,然而……
时代变了,进入大学的笔者也有幸加入了一个工程性的项目组,写了廖廖几千行的工程性代码。
天哪,每当我打开一个月之前的代码时,我都要鼓起莫大的勇气,边看着边咒骂着一个月前的自己。
当一个函数套一个try-catch成为习惯,if的缩进套五六层成为常态,字典找不到key的报错成为日常,很显然我也成为了创造屎山代码的一员。
这篇文章的产生背景就是这样,我希望以Python为例子,回顾一下如何写出优雅的代码。当然,由于熵增定律的存在,你最终可能还是会创作出一个属于你的屎山(笑),但是笔者寄希望于这篇文章能让你在读自己屎山的时候能减少一点负罪感(大笑)
本次Python优雅计划(又称:屎山消消乐计划,乐) 将分为代码规范、模块化编程、Python小技巧和异常处理这四个章节来介绍,或在一篇文章中,或分为两篇文章进行实用性的阐述。

一、代码规范

或许在做题时,使用各种稀奇古怪的 变量名||函数名 还能解释为整活,那么在工程性代码里使用包括但不限于拼音、abc、func123这种玩意无疑是对一个月之后的自己和未来可能把你这坨大的吃下去的人的折磨。
显然,不同的场景下,不同的人可能会有不同的习惯。笔者只是介绍一下笔者比较偏爱的编码规范,供给各位参考,也是抛砖引玉。

1.变量名

主流分为三种:单驼峰、下划线和多驼峰
单驼峰一般将最重要的部分突出,多驼峰将各个名词的首字母都大写,下划线将各个单词之间用下划线隔开。
例如一个user类需要存储用户的用户名、uuid、密码、状态等内容
单驼峰:userName userID userPasswd userStatus
多驼峰:UserName UserID UserPasswd UserStatus
下划线:user_name user_id user_passwd user_status

其中还有一些小技巧,
在变量名前加上这个变量的类型(可以使用一些约定俗称的类型缩写,或者在代码开头就提前说明一些常用的缩写),struserName intuserID等,可以更方便的确定变量的类型;
在Python中,变量前加上双下划线__可以代表其权限为私有,只在该类或者该文件中使用,可以有效避免外部访问,保证其封装性。
值得注意的是,循环变量不一定一定是约定俗称的ijk,以下这个例子可以更直观的说明循环变量重新命名的好处

1
2
3
4
5
6
7
users=[(1,"a",90),(2,"b",80),(3,"c",99)]
# 使用ijk传统写法
for i in users:
print(i[0],i[1],i[2])
# 使用更为形象的循环变量
for id,name,score in users:
print(id,name,score)

显然当我们使用更为形象的循环变量名时,大大降低了阅读代码是的思维负担。

2.函数名

函数名的命名方式同变量,但是需要补充一些额外内容。
由于函数通常是对数据进行一些处理或者完成一些动作,所以一般可以采用动宾结构。例如判断素数函数可以命名为isPrime,判断是否存在可以命名为isExist,根据ID移除某项可以命名为removeByID等

除此之外,还有类名规范、接口规范等很多命名规范,有很多有专门的命名规则,例如RESTful类型的api接口命名规范等,便不在一一介绍。
在我们的个人项目里,或许我们可以按照自己的喜好去命名各种变量或接口,但是在一个整体性的大项目里,项目的领导者去制定一套简洁且完善的命名规范敦促各个写代码的人去执行,至关重要。

二、模块化编程

笔者想起曾经为了赶ddl,慌不择路的把几十个函数写进一个文件的惨痛经历。为了避免未来的你因为阅读代码而掉头发,我们要学会模块化编程。

1.模块分离

模块化编程的核心思想就是将复杂的问题分解成小的、易于管理的部分。举个简单的例子,如果你在做一个用户管理系统,不要一股脑把用户注册、登录、权限管理这些功能都写在一个文件里,而是分别建立不同的模块,每个模块只负责一个功能。
例如,可以这样组织代码结构:

1
2
3
4
5
user_management/
__init__.py
registration.py
login.py
permissions.py

然后在各个模块中分别实现相应的功能:

1
2
3
4
# registration.py
def register_user(username, password):
# 注册用户的逻辑
pass
1
2
3
4
# login.py
def login_user(username, password):
# 用户登录的逻辑
pass
1
2
3
4
# permissions.py
def check_permission(user, action):
# 权限检查的逻辑
pass

在主进程中通过import模块把这些函数分别注入,可以实现逻辑分离

2.多文件夹组织结构

合理的文件夹结构会让你的代码看起来井井有条,方便管理和维护。
例如,你可以按功能模块来组织代码文件夹:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
project/
main.py
utils/
__init__.py
file_operations.py
data_processing.py
models/
__init__.py
user_model.py
product_model.py
services/
__init__.py
user_service.py
product_service.py

3. 依赖管理

模块化编程还有一个重要的好处就是可以有效管理模块之间的依赖。我们可以通过模块的接口暴露功能,而隐藏具体实现,从而减少模块之间的耦合。这种方式不仅让代码更易于维护,还能方便模块的替换和升级。

1
2
3
4
5
6
# user_management/__init__.py
from .registration import register_user
from .login import login_user
from .permissions import check_permission

__all__ = ["register_user", "login_user", "check_permission"]

通过这种方式,你可以在外部模块中方便地使用这些功能,而不必关心它们的具体实现细节。

1
2
3
4
5
# main.py
from user_management import register_user, login_user, check_permission

# 使用注册功能
register_user("john_doe", "secure_password")

总之,模块化编程不仅是写出优雅代码的关键,更是让你在阅读和维护代码时减少“痛苦指数”的重要手段。

——————————————未完待续——————————————