Python“唯一的方法”的具体示例maxim [关闭]


34

我正在学习Python,并对PEP 20 The Zen of Python中的以下几点感兴趣:

应该有一种-最好只有一种-显而易见的方法。尽管除非您是荷兰人,否则一开始这种方式可能并不明显。

谁能提供这个格言的具体例子?我对与其他语言(例如Ruby)的对比特别感兴趣。Ruby设计哲学的一部分(我认为起源于Perl?)是实现它的多种方法。任何人都可以提供一些示例来说明每种方法的利弊。请注意,我不是在寻找哪个更好的答案(这可能是主观的,无法回答),而是两种风格的公正对比。

Answers:


47

与Perl之类的语言相比,Python的控件构造数量有限:

  • 只有if而没有unless
  • for在序列上进行迭代,并且没有no foreach或C样式for
  • 只有while这样才能在每个循环中检查条件,并且没有do-while
  • 只有if-elif而没有switch
  • 仅有一个注释构造,#并且,无需查看前几行,您就可以知道每一行是否被注释掉。

而且,几乎有一种方法可以使您的源代码缩进。从句法上讲,大多数创意缩进都被排除在外。

这使人类更容易解析Python源。

尝试将内置类型和标准库的内容减到最少,但要完整。

  • 对于可变列表,您使用唯一的内置list类型;大多数操作为O(1),而您不必选择正确的实现,
  • 对于不可变列表,同样地,您只需使用tuple类型,
  • 对于地图,您可以使用唯一dict在大多数情况下非常有效的内置函数,而无需考虑使用哪种实现。

Python 3将其扩展为整数:不管整数有多大,您都使用相同的类型,并且从不关心强制。

Python尝试避免语法糖。但是有时它添加语法糖只是为了使显而易见的方式变得明显。您可以写if foo is not None而不是if not (foo is None)因为“ is not”是特殊情况。仍然foo is not None易于阅读,不会被误解,您不必思考,您只需写显而易见的东西。

当然,Python中大多数更复杂的事情可以通过几种方法来完成。您可以通过声明或通过简单的插槽分配将方法添加到类中,也可以通过许多创造性的方式将参数传递给函数,等等。这仅仅是因为该语言的内部大部分都公开了。

关键在于,总有一种情况是最好的一种方法。如果存在其他方式,则不会将它们作为相等的替代项(例如ifunless)添加,而只是公开内部工作原理。通过增强已知的最佳机制,这种替代方法逐渐但稳定地被淘汰(未消除!)。

装饰器包装AOP函数调用。在2.6之前,您必须使用__metaclass__magic成员声明类的元类;现在,您也可以为此使用相同的装饰器语法。在3.0之前,您有两种字符串,面向字节的字符串和Unicode,您可能会无意间将它们混合使用。现在,您拥有唯一的Unicode str和唯一的二进制透明的bytes,您不能将其错误混合。


3
只是作为注释,请不要忘记"""注释(文档字符串)。这些跨越多行。
asthasr 2011年

8
用三引号引起来的文字只是字符串,与单引号相同,但是可以跨越多行而不会转义行尾。声明后的字符串文字被视为文档字符串,它不是注释,通常可以作为__doc__属性访问。但是字符串是Python绝对提供许多“正确方法”的领域:使用单引号,双引号或三引号,隐式联接相邻的文字,r用于原始文字等
9000

1
我觉得@ syrion的评论是关于“你总是可以决定一个线是否是通过看它的评论或不”,这是因为“””字符串不正确的。
blubb

2
“这使人类更容易解析Python源。” <-这是主观的
jiggy

元类声明在2.7中如何更改?在2.7文档中找不到元类的装饰器模式。
尼克T

10

另外两个例子是:
len()是一个函数而不是每个序列中都有一个方法;如果你使用Java比较你有.length.size().getSize(),等方法来寻找序列中的元素的数量。

另一个例子是事实,.join()string不是每个序列中都存在的一种方法。您无需知道join参数是列表,集合,理解还是任何其他形式,它将起作用。


8

在C语言中,有许多种方法可以将变量的值增加一:

i++     // Post-increment, returns the number before the increment
++i     // Pre-increment, returns the number after the increment
i += 1 

每个最终都会增加iby 的值1,但是每个都略有不同。

在Python中,实际上只有一种方法。只需添加一个。

i += 1

尽管有多种语法上有效的方法可以做到这一点(例如i = i + 1),但是您在做同样的事情却具有相同的副作用。


1
我不是专家,但是该示例似乎恰恰违反了“唯一的方法”。我们有两种方法可以做到,但是哪一种更明显呢?在我看来,第一个示例更为明显,而第二个示例则更为简洁,但对于任何已超越基础知识的程序员而言,其可读性或显而易见性都没有。谢谢您的回答-这是值得深思的食物。
Charles Roper

@Peter(和@Charles):实际上,i = i + 1是分配,而不是增量。在python中,增量为i += 1。在C风格的语言,你可以写i++++ii += 1
乔什K

2
不确定您的“困惑”注释,您的所有三个C示例(您错过了i += 1,BTW)都会产生完全相同的结果。我唯一一次看到人们感到困惑的是,他们在一个较大的表达式中对变量进行预增或后增,通常可以通过阅读语言参考的相应章节来快速纠正。就我个人而言,我会选择一个事实,即您可以通过str[4]或来引用字符串的第五个字符*(str+4),但这也许太容易了……
TMN

2
@TMN:在某些情况下,例如max(i++, ++i)无法迅速纠正。C有很多“未定义”和“依赖实现”的行为案例,这都是有充分理由的,但是每个案例都会带来一个陷阱。
9000

@TMN:更不用说4 [str](在C中有效,在C ++中可能无效)。
瓦汀

6

另一种可能是列表理解。在Python中,您可以这样做:

new_list = []
    for item in list_of_items:
       if item < 10:
           new_list.append(item)

但是,这样做的“明显”方式(如果您是荷兰人或更熟悉Python)将与列表理解有关:

new_list = [item for item in list_of_items if item < 10]

它更短,只需一步就可以创建new_list,我相信它运行得更快,而且优雅。不利的一面是,人们可能会认为它不太明确,但我认为,一旦您习惯了它,它就会变得同样明确。


对于缩进和代码:在其前面加上4个空格,然后它将尊重缩进。
印加
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.