The Python IAQ: Infrequently Answered Questions
1 Q: 什么是”少有人回答的问题(Infrequently Answered Question)” ?
一个问题之所以很少有人回答,要么是因为很少有人知道问题的答案,要么是因为它涉及到一个晦涩而隐蔽的知识点(但可能是你关心的)。我过去认为是我在Java IAQ中发明了这个词组,但是它也出现在了以数据丰富而著称的About.com Urban Legends网站上. 关于Python的FAQ有很多,但是Python的IAQ只有这一个。(“少见问题列表”倒是有一些,其中一个是有讽刺意味的C。)
2 Q: finally子句中的代码每次都会被执行,对吗?
每次?应该说,几乎每次。在try子句被执行后,无论是否出现异常,finally子句中的代码都会被执行,即使调用了sys.exit. 不过如果程序没有执行到finally子句的话,它就没有办法运行了。下面的代码中,无论choice取何值,都会发生这样的情况:
try:
if choice:
while 1:
pass
else:
print “Please pull the plug on your computer sometime soon…”
time.sleep(60 * 60 * 24 * 365 * 10000)
finally:
print “Finally …”
3 Q: 多态真是太棒了!无论一个列表(list)中的元素是什么类型,我都可以用sort对它排序,对吗?#
不对。考虑这种情况:
x = [1, 1j]
x.sort()
Traceback (most recent call last):
File “<pyshell#13>”, line 1, in ?
x.sort()
TypeError: cannot compare complex numbers using <, <=, >, >=
(1j是一个数,表示-1的平方根)问题在于:sort方法(在目前的实现中)使用lt方法来 比较元素的大小。而lt方法拒绝比较复数的大小(因为它们是不能排序的)。奇怪的是, complex.lt会毫不犹豫的比较复数与字符串,列表(list)和其他所有类型,除了复数。所以答案是,你可以对支持lt方法的对象序列(sequence)进行排序(当然如果将来实现变了,可能就是其它方法了)。
对于问题的地一部份,“多态真棒”,我同意。但是Python有时会让使用多态变得困难,因为许多Python的类型(比如序列和数)的定义不太符合规则。
4 Q: 在Python中我能写++x和x++吗?
从语法上说,++x能, x++不能。但是从实际使用来说,别这样做。这么说什么意思?
可以, ++x是合法的Python语法。不过如果你是一个C++或者Java程序员的话,它表示不是你想的那个意思。加号+是一个单目前缀操作符,所以++x被解析为+(+x),它表示的(至少对于数字来说)就是x。
不可以, x++本身就不是一个合法的表达式, 虽然在某些上下文时合法。比如, x++ -y被解析为x++(-(y)), 对于数字来说,等于x - y。当然,你可以创建一个类,让++x有(很有限的)意义。比如可以让这个类保存一个数字,然后使单目操作符+使它增加0.5(或者有0.5的概率增加1,如果你喜欢随机化算法),但是…
不可以,那样真傻。最好还是用Python 2.0已经中加入的x += 1。 进一步的问题:为什么Python不允许 x++? 我相信原因与Python不允许在表达式中赋值一样: Python想要清晰的区分语句和表达式。如果我觉得这两者应该有所区别,那么不允许++就是最好的决定。另一方面,函数语言的鼓吹者认为语句就应该是表达式。我跟我的丹麦老乡,Bjarne Stroustrup,都这样认为。他在The Design and Evolution of C++中说:“如果是从头来设计一种语言的话,我会按照Algol68的方式,让每条语句和声明都是一个有返回值的表达式”。
5 Q: 我能使用C++中对ostreams那样的语法吗,像这样么: count << x << y …?#
当然可以。如果你不喜欢写”print x,y”,你可以试试这个:
import sys
class ostream:
def init(self, file):
self.file = file
def __lshift__(self, obj):
self.file.write(str(obj));
return self
cout = ostream(sys.stdout)
cerr = ostream(sys.stderr)
nl = ‘\n’
cout << x << " " << y << nl
(本文中所有的文件中的代码都在横线以上,使用这些代码的例子在横线以下。)这样你就可以使用一种不同的语法了,但是它不能给你带来一种新的输出格式,它只是把Python中以有str的格式封装了一层而已。这个做法很像Java里面的toString()格式。C++使用的是一种迥异的格式:它没有定义一组把对象转换为字符串的规则,而定义了一种把对象打印到流的规则(也许是不完整的规则,因为很多C++程序仍然使用printf)。用流来实现会更加复杂,但是它的优势在于如果你需要打印一个相当巨大的对象,就不用创建一个巨大的临时对象来做这件事。
6 Q: 如果我喜欢C++的printf呢?#
在Python中定义一个printf不是一个坏主意. 你可能认为printf(“%d = %s”, num, result)比print “%d = %s” % (num, result)更加自然, 因为那一对括号在更熟悉的位置(而且你不想要那个%)。更和况, 满足这个需求轻而易举:
def printf(format, *args): print format % args,
即使是像这样的一行代码,也有几个不同实现。首先,我必需要决定是否在结尾添加逗号。为了更像C++, 我决定加上(这就意味着如果你想在结尾换行,你需要自己在格式字符串的末尾添加)。其次,结尾处会打印一个空格。如果你不想要它,使用sys.stdout.write来代替print. 最后, 把一切都变得更像C好是一件好事吗? 是,因为你需要一个打印函数(而不是一个打印语句)在只接受函数不接受语句的地方使用。比如,在lambda表达式中和map的第一个参数。事实上,这样一个函数使用起来是很趁手的,你可能想要一个没有格式化功能的:
def prin(x): print x,
现在map(prin, seq)将打印seq中的每一个元素. 但是map(print, seq)是一个语法错误. 我曾经见过有些粗心大意的程序员(好吧, 没错, 我自己就是. 但是我知道我自己很粗心 )认为把这两个函数合二为一是个好主意, 像这样:
def printf(format, *args): print str(format) % args,
这样 printf(42), printf(‘A multi-line\n message’)和 printf(‘%4.2f’, 42)都能工作。但是当你用了pring(‘100% guaranteed’)或者是其他任何含有%字符却并不是一个格式化指令时,”好主意”就会变成”我想啥呢?”。如果你真的实现了这么一个printf,它需要这样的注释:
def printf(format, *args):
“”“使用第一个参数作为格式字符串来格式化args, 然后打印.
如果format不是字符串, 将被str转换成字符串. 如果x可能含
有%和反斜杠字符, 你必须使用printf(’%s’, x)来代替 printf(x).
“””
print str(format) % args,
7 Q: 关于字典(Dictionary),有没有更好的语法? 我使用的键(key)都是标识符.#
有!用一对引号来包括键的确是一件麻烦的事情,尤其当键是一个很长的字符串时. 起初我认为Python中加入特别的语法是有帮助的,用{a=1, b=2}来代替现在必需的{‘a’:1, ‘b’:2}。在Python 2.3中,你可以用的语法是dict(a=1, b=2, c=3, dee=4),这和我的想法一样好。在Python 2.3以前,我使用一个只有一行的函数:
def Dict(**dict): return dict
一个读者指出,对于散列Perl也有类似的特殊符号: 在Perl中对于散列文本,你可以写(“a”, 1, “b”, 2)或者(a=>1, b=>2)。这是事实,但不是事实的全部。”man perlop”说”=>符号最多只是逗号操作符的同意词…”而且事实上当a和b是barewords时,你可以写(a, 1, b, 2)。但是,就像Dag Asheim指出的,如果你打开strict,你将会从这个写法中得到一个错误。你必须要么使用字符串,要么使用=>操作符。最后,Larry Wall已经申明,”Perl 6中将不会有bareword”。(关于perl的这以部分,我的翻译可能有很大问题,因为我根本不会Perl! –译注)
函数是很像的)。我讨厌再给Struct添加什么了,因为它现在很简洁,不过如果你添加下面的方法,就可以漂亮打印出它的每个结构。
最后,小编想说:我是一名python开发工程师,
整理了一套最新的python系统学习教程,
想要这些资料的可以关注私信小编“01”即可。