你的代码“balance”怎么样?找到简洁性和可读性的平衡点

论坛 期权论坛 脚本     
已经匿名di用户   2022-7-2 21:57   1217   0


全文共3164字,预计学习时长16分钟

图源:unsplash

Python对初学者非常友好,许多人在开始学习编程时都会选择Python。简单易上手是你接触它之后发现的第一个优点。进一步了解之后,你可能会被它的灵活性所吸引——可通过各种方式做同一功能。

事实上,还有更便捷的解决方案。代码越简洁,可读性越高且能够长期存在。用Python编写简洁代码的方法有很多,本文想与大家分享笔者在日常Python项目中发现的特别有用的五个技巧。

1.列表、字典和集合推导式

列表推导式是众多Python程序员最喜欢的特征之一。这是一种从迭代器创建列表的简洁方法。基本语法是[expression for x in iterable]。可以看一些示例进一步了解其用法:

>>># Create a list for subsequentoperations          >>> numbers = [1, 2, 3, 4, 5, 6]          >>>>>># Typical way to create a list consisting of squares          >>> squares0 = []          >>>for number in numbers:          ...     squares0.append(number*number)          ...          >>># List comprehensions          >>> squares1 = [number*number for number in numbers]

在不使用列表推导式的情况下,必须创建一个空列表,并通过运行for循环来添加每个数字的平方,这通常需要三行代码。使用列别推导式后,只需一行代码即可构建相同的平方列表。

除了列表推导式,还有字典和集合推导式。字典推导式有该基本语法 {key_expr:value_expr for x in iterable},集合推导式的基本语法是 {expressionfor x in iterable}。与列表推导式示例类似,不使用推导式的情况下,需要多行代码来构建所需的字典和集合。

>>># Dictionary comprehension             >>> squares_dict = {number: number*number for number in numbers}             >>> squares_dict             {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36}             >>>>>># Set comprehension             >>> numbers_dups = [1, 2, 3, 4, 3, 2, 1]             >>> squares_set = {number*number for number in numbers_dups}             >>> squares_set             {16, 1, 4, 9}

2.Lambda函数

Lambda函数是Python中的匿名函数,通常用于小规模操作。Lambda函数可以接受一到多个参数,只需一个表达式,其语法为lambda parameters:expression。

图源:pixabay

笔者将使用内置sorted()函数演示lambda函数的用法。具体而言,sorted()函数会使用key函数对迭代进行排序,该函数由key参数指定。我们可以将lambda函数作为key参数,而不是用def关键字声明常规函数。

>>># Create a list of students with theirgrading information           >>> grades = [{ name :  John ,  grade : 95}, { name :  Aaron ,  grade : 92}, { name :  Jennifer ,  grade : 100}]           >>>>>># Sort using a regular function           >>>defsort_grade(student):           ...     return student[ grade ]           ...           >>>sorted(grades, key=sort_grade)           [{ name :  Aaron ,  grade : 92}, { name :  John ,  grade : 95}, { name :  Jennifer ,  grade : 100}]           >>>>>># Sort using a lambda           >>>sorted(grades, key=lambda x: x[ grade ])           [{ name :  Aaron ,  grade : 92}, { name :  John ,  grade : 95}, { name :  Jennifer ,  grade : 100}]

如上所示,使用lambda函数可以编写出更简洁的调用sorted()函数的命令。在使用正则表达式之前,必须先声明该函数,然后才能使用sorted()函数,这一定比直接使用lambda函数更繁琐。

3.命名元组作数据结构

元组可以存储一些相关数据,但是使用起来并不顺手,特别是涉及特定元素时,必须记住顺序并使用特定元素的正确索引。如果不想使用元组,虽然可以构建一个自定义类来管理相关数据,但namedtuple数据类型是一种非常有用的轻量级数据结构。

通过集合模块,namedtuple数据类型采用以下基本语法:namedtuple(Typename,field_names)。语法并不直截了当,不过从概念上来说是容易理解的。

来看看示例。理想的特性是创建一个可以存储学生信息的数据结构,包括姓名、性别和学生ID号。

>>># Use a custom class      >>>classStudent0:      ...     def__init__(self, name, gender, student_id):      ...         self.name = name      ...         self.gender = gender      ...         self.student_id = student_id      ...      >>> s0 =Student0( John ,  M , 2020001)      >>>f"Name: {s0.name}; Gender: {s0.gender}; ID #: {s0.student_id}"       Name: John; Gender: M; ID #: 2020001       >>>>>># Use the namedtuple      >>>from collections import namedtuple      >>>Student1=namedtuple("Student1", ["name", "gender", "student_id"])      >>> s1 =Student1( Jennifer ,  F , 2020002)      >>>f"Name: {s1.name}; Gender: {s1.gender}; ID #: {s1.student_id}"       Name: Jennifer; Gender: F; ID #:2020002 

使用namedtuple模块,可以用更简洁的代码编写轻量级数据结构。当然,请注意,自定义类提供了更多可以操作的功能。但如果只是为了存储和检索数据而创建一个数据结构,完全可以考虑使用namedtuple模块。

图源:unsplash

4.使用enumerate()和zip()进行迭代

编码的一个关键原则是精简。当处理一系列数据(如数字列表)时,通常需要对列表中的每个数字执行相同的操作。为了避免重复相同的代码,可以使用for循环loop来运行整个列表的迭代。

当迭代一个列表或任何序列时,有时还需要知道该项在序列中的位置。下面几种方法可以做到这一点。

>>># Create a list of students based ontheir arrival sequence        >>> students = [ John ,  Aaron ,  Jennifer ,  Ashley ]        >>>>>># Lengthy way        >>>for index inrange(len(students)):        ...     student = students[index]        ...     print(f"Arrival # {index+1}: {student}")        ...        Arrival# 1: John        Arrival# 2: Aaron        Arrival# 3: Jennifer        Arrival# 4: Ashley        >>>>>># Concise way        >>>for index, student inenumerate(students, 1):        ...     print(f"Arrival # {index}: {student}")        ...        Arrival# 1: John        Arrival# 2: Aaron        Arrival# 3: Jennifer        Arrival# 4: Ashley

通过使用内置函数enumerate(),可以轻松访问序列中的索引和元素,这比第一次迭代更简洁。更重要的是,它可以设置开始计数的数字。在上面的示例中设置为了1。

除了enumerate()函数,zip()函数在迭代中也颇为有用。此函数可以从多个迭代中创建元组,而无需特意为这些迭代创建复合迭代。

>>># Create two lists for zip(), with oneto one match      >>> names = [ John ,  Danny ,  Jennifer ]      >>> scores = [95, 99, 100]      >>>>>># Lengthy way      >>>for index inrange(len(names)):      ...     name, score = names[index], scores[index]      ...     print(f"Name: {name}; Score: {score}")      ...      Name: John; Score: 95      Name: Danny; Score: 99      Name: Jennifer; Score: 100      >>>>>># Concise way      >>>for name, score inzip(names, scores):      ...     print(f"Name: {name}; Score: {score}")      ...      Name: John; Score: 95      Name: Danny; Score: 99      Name: Jennifer; Score: 100

基本上,zip()函数所做的就是从迭代中获取每个元素,以便在每次迭代中形成一个有顺序的元组。这样一来代码会更简洁,可读性也更高。

图源:unsplash

5.f字符串格式化

字符串太基础了,我们基本上在哪都会用它。字符串的一个基本应用是与某些格式一并使用。有几种格式化字符串的方法,笔者想介绍的是f字符串,这个方法非常简单。

f字符串是使用字母f(或F)作为字符串文本的前缀插入的字符串文本。为了编写简洁的代码,下面两个用例首选f字符串:

· 显示变量。最基本的用法是显示一些变量的值,以便在开发过程中进行调试。如果使用传统的format()方法,代码会偏长。

>>># Construct a list for formatting/debugging                            >>> prime_numbers = [2, 3, 5, 7, 11]                            >>>>>># Show the list using format                            >>>print("Prime Numbers: {}".format(prime_numbers))                            PrimeNumbers: [2, 3, 5, 7, 11]                            >>>>>># Show the list using f-string                            >>>print(f"Prime Numbers: {prime_numbers}")                            PrimeNumbers: [2, 3, 5, 7, 11]

· 加入变量/连接字符串。f字符串不是使用+和字符串的join()方法,而是非常直接地用于字符串连接,并且它们具有最高的可读性。在实际操作中可用于构造文件路径,如下所示:

>>># The folder and extension                 >>> folder = ./usr/images                  >>> ext = .jpg                  >>>>>># File name is computed from this list                 >>> names = [10, 11, 12]                 >>>>>># Construct File paths                 >>># Use + for concatenation                 >>> paths0 = [folder + / +str(x) + ext for x in names]                 >>>>>># Use join()                 >>> paths1 = [  .join([folder,  / , str(x), ext]) for x in names]                 >>>>>># Use f strings                 >>> paths2 = [f"{folder}/{x}{ext}"for x in names]

图源:pixabay

编写越简短,代码的可读性和可维护性就会得到实际的提高,这是亘古不变的真理。但请记住,简洁的代码不应该带来任何潜在的歧义或混淆。

你必须在简洁性和可读性之间寻求平衡点。一旦发生冲突,首先考虑可读性,哪怕这会需要更多的代码。


推荐阅读专题

留言点赞发个朋友圈

我们一起分享AI学习与发展的干货

编译组:苏韫琦、高洋

相关链接:

https://medium.com/better-programming/5-tricks-to-write-more-concise-python-code-f075f66336b6

如转载,请后台留言,遵守转载规范

推荐文章阅读

ACL2018论文集50篇解读

EMNLP2017论文集28篇论文解读

2018年AI三大顶会中国学术成果全链接

ACL2017论文集:34篇解读干货全在这里

10篇AAAI2017经典论文回顾

长按识别二维码可添加关注

读芯君爱你

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP