返回介绍

建议1:理解 Pythonic 概念

发布于 2024-01-30 22:19:09 字数 4014 浏览 0 评论 0 收藏 0

什么是Pythonic?这是很难定义的,这就是为什么大家无法通过搜索引擎找到准确答案的原因。但很难定义的概念绝非意味着其定义没有价值,尤其不能否定它对编写优美的Python代码的指导作用。

对于Pythonic的概念,众人各有自己的看法,但大家心目之中都认同一个更具体的指南,那就是Tim Peters的《The Zen of Python》(Python之禅)。在这一充满着禅意的诗篇中,有几点非常深入人心:

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

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

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

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

(1)Pythonic的定义

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

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 'pivot' from 'array'  // see 'Choice of pivot' below
  create empty lists 'less' and 'greater'
  for each 'x' in 'array'
    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自身特色的代码风格。接下来就看看这样的代码风格在实际中是如何体现的。

(2)代码风格

对于风格,光说是没有用的,最好是通过例子来看看,因为例子看得见,会显得更真实。下面以语法、库和应用程序为例给大家介绍。

在语法上,代码风格要充分表现Python自身特色。举个最常见的例子,在其他的语言(如C语言)中,两个变量交换需要如下的代码:

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

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

a, b = b, a

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

length = len(alist)
i = 0
while i < length:
  do_sth_with(alist[i])
  i += 1

而 Pythonic的代码如下:

for i in alist:
  do_sth_with(i)

灵活地使用迭代器是一种Python风格。又比如,需要安全地关闭文件描述符,可以使用以下with语句:

with open(path, 'r') as f:
  do_sth_with(f)

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

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

a = [1,2,3,4]
c = 'abcdef'
print a[::-1]
print c[::-1]

如果不是同样追求每一个语法细节的“老鸟”,这段代码的作用恐怕不能一眼就看出来。实际上,这个时候更好地体现Pythonic的代码是充分利用Python库里reversed()函数的代码。

print list(reversed(a))
print list(reversed(c))

(3)标准库

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

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

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

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

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

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

%占位符来自于大家的先验知识,其实对于新手而言,有点“莫名其妙”,所以更具有Pythonic风格的代码如下:

print '{greet} from {language}.'.format(greet = 'Hello world', language = 'Python')

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

(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()

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

另一个有关新趋势的例子是:Python的包和模块结构日益规范化。现在的库或框架跟随了以下潮流:

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

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

[1] http://en.wikipedia.org/wiki/Quicksort。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文