>>> from env_helper import info; info()
页面更新时间: 2023-12-27 09:18:58
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-16-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

1.1. 理解Pythonic概念

什么是Pythonic?这是很难定义的,这就是为什么大家无法通过搜索引擎找到准确答 案的原因。但很难定义的概念绝非意味着其定义没有价值,尤其不能否定它对编写优美的 Python代码的指导作用。 对于Pythmiic的概念,众人各有自己的看法,但大家心目之中都认同一个更具体的指 南,那就是Tim Peters的《The Zen of Python》(Python之禅)。在这一充满着禅意的诗篇中,有几点非常深入人心:

  • 美胜丑,显胜隐,简胜杂,杂胜乱,平胜陡,疏胜密。

  • 找到简单问题的一个方法,最好是唯一的方法(正确的解决之道)。

  • 难以解释的实现,源自不好的主意;如有非常棒的主意,它的实现肯定易于解释。

不仅这几点,其实《Python之禅》中的每一句都可作为编程的信条。 是的,不仅是作为 编写Python代码的信条,以它为信条编写出的其他语言的代码也会非常漂亮。

1.1.1. Pythonic 的定义

遵循Pythonic的代码,看起来就像是伪代码。其实,所有的伪代码都可以轻易地转换为 可执行的Python代码。比如在Wikipecha的快速排序e条目中有如下伪代码:

function quicksort('array')
if length('array') <= 1

return 'array' //an array of zero or one elements is already sorted select and remove a pivot element 1 pivot1 from 'array'

see 'Choice of pivot1 below create empty lists 'less 1 and *greater 1 ''' for each 'x1 in rarray'

if 'x' <='pivot' then append 'x' to 'less' else append 'x' to 'greater'

return concatenate(quicksort <('less'), list('pivot'), quicksort('greater'))

//two recursive calls

实际上,它可以转化为以下同等行数的可以执行的Python代码:

>>> def quicksort(array):
>>>     less=[];
>>>     greater =[]
>>>     if len(array) <=1:
>>>         return array
>>>     pivot = array.pop()
>>>     for x in array:
>>>         if x <= pivot: less.append(x)
>>>         else: greater.append(x)
>>>     return quicksort (less) + [pivot]+quicksort(greater)

看,行数一样的Python代码甚至可读性比伪代码还要好吧?但它真的可以运行,结果如下:

>>>  quicksort ([9, 8,4, 5,32,64,2,1,0, 10, 19,27])
[0, 1, 2, 4, 5, 8, 9, 10, 19, 27, 32, 64]

所以,综合这个例子来说,Pythonic也许可以定义为:充分体现Python自身特色的代码风格。 接下来就看看这样的代码风格在实际中是如何体现的。

1.1.2. 代码风格

对于风格,光说是没有用的,最好是通过例子来看看,因为例子看得见,会显得更真实。 下面以语法、库和应用程序为例给大家介绍。 在语法上,代码风格要充分表现Python自身特色。 举个最常见的例子,在其他的语言 (如C语言)中,两个变量交换需要如下的代码:

int a = 1, b = 2; int tmp - a; a-b; b =tmp;

利用Python的 packaging/unpackaging 机制,Pythonic的代码只需要以下一行:

>>> a=1
>>> b=2
>>> a,b = b,a

还有,在遍历一个容器的时候,类似其他编程语言的代码如下:

>>> def do_sth_with(n):
>>>     print(n)
>>>
>>> alist=[1,2,43,5,4]
>>> length = len(alist)
>>> i =0
>>> while i < length:
>>>     do_sth_with(alist[i])
>>>     i+=1
1
2
43
5
4

而Pythonic的代码如下:

>>> for i in alist:
>>>     do_sth_with(i)
1
2
43
5
4

灵活地使用迭代器是一种Python风格。

又比如,需要安全地关闭文件描述符,可以使用以下 with 语句:

>>> with open('test_1.txt','r') as f:
>>>     do_sth_with(f)
<_io.TextIOWrapper name='test_1.txt' mode='r' encoding='UTF-8'>

通过上述代码的对比,能让大家清晰地认识到Pythonic的一个要求, 就是对Python语 法本身的充分发挥,写出来的代码带着Python味儿而不是看着像C语言代码,或者Java 代码。

应当追求的是充分利用Python语法,但不应当过分地使用奇技淫巧,比如利用Python 的 Slice 语法可以写出如下代码:

>>> a = [1,2,3,4]
>>> c = 'abodef'
>>> print (a[::-1] )
>>> print (c[::-1])
[4, 3, 2, 1]
fedoba

如果不是同样追求每一个语法细节的”老鸟”,这段代码的作用恐怕不能一眼就看出来。

实际上,这个时候更好地体现Pythonic的代码是充分利用Python库里 reversed() 函数 的代码。

>>> print (list(reversed(a)))
>>> print (list(reversed(c)))
[4, 3, 2, 1]
['f', 'e', 'd', 'o', 'b', 'a']

1.1.3. 标准库

写Pythonic程序需要对标准库有充分的理解,特别是内置函数和内置数据类型。比如,对于字符串格式化,一般这样写:

>>> print ('Hello %s!' % ('Tom',))
Hello Tom!

其实是非常影响可读性的,因为数量多了以后,很难清楚哪一个占位符对应哪一个 实参。所以相对应的Pythonic代码是这样的:

>>> print('Hello %(name)s!' % {'name':'Tom'})
Hello Tom!

这样在参数比较多的情况下尤其有用。

>>> #字符串
>>> value = {'greet':'Hello world', 'language':'Python'}
>>> print ('%(greet)s from %(language)s.' % value)
Hello world from Python.
>>> print(
>>>     '{greet} from {language}.'.format(
>>>         greet = 'Hello world',
>>>         language =' Python')
>>>       )
Hello world from  Python.

str.format() 方法非常清晰地表明了这条语句的意图, 而且模板的使用也减少了许多不必要的字符,使可读性得到了很大的提升。 事实上,str.format() 也成了 Python最为推荐的字符串格式化方法,当然也是最Pythonic的。

1.1.4. Pythonic的库或框架

编写应用程序的时候的要求会更高一些。因为编写应用程序一般需要团队合作, 那么可 能你编写的那一部分正好是团队的另一成员需要调用的接口,换言之,你可能正在编写库或 框架。 程序员利用Pythonic的库或框架能更加容易、更加自然地完成任务。 如果用Python编 写的库或框架迫使程序员编写累赘的或不推荐的代码, 那么可以说它并不Pythonic。 现在业内通常认为Flask这个框架是比较Pythonic的,它的一个Hello world级别的用例如下:

>>> # from flask import Flask
>>> # app = Flask( __name__ )
>>> # @app.route('/')
>>> def hello():
>>>     return "Hello world!"
>>>
>>> if __name__ == '__main__':
>>>    # app.run()
>>>
>>>     print(hello())
Hello world!

稍有编程经验的人都可以通过上例认识到利用Python编程极为容易这一事实。 一个 Pythonic的框架不会对已经通过惯用法完成的东西重复发明“轮子”,而且它也遵循常用的 Python惯例。 创建Pythonic的框架极其困难,什么理念更酷、更符合语言习惯对此毫无帮助,事实上这些年来优秀的Python代码的特性也在不断演化。 比如现在认为像 generators 之类的特性尤为Pythonic。 另一个有关新趋势的例子是:Python的包和模块结构日益规范化。 现在的库或框架跟随了以下潮流:

  • 包和模块的命名釆用小写、单数形式,而且短小。

  • 包通常仅作为命名空间,如只包含空的 _init_.py 文件。