郑渊洁说过一般来说,人是身上缺什么吆喝什么。观察人的诀窍是反着听他的话。
Python吆喝的是什么呢?PEP 20 是这么写的:There should be one-- and preferably only one --obvious way to do it.
在某些语言里,原生资源要通过finally语句来保证释放,比如Java/C#,另一些语言有析构函数,所以就不需要finally语句,比如C++。
再看Python,Python里有个__del__魔法函数,在垃圾收集时触发。考虑到Python具有引用计数功能,实际上__del__完全可以保证局部变量用完后立即触发。所以只要把资源释放放到__del__,就可以跟C++的析构函数一样可以管理原生资源。
不幸的是,Python除了C++一样的__del__,还提供了还有finally。 甚至还嫌不够,搞了第三套资源管理方式:即with/__enter__/__exit__ 。
作为一个Python 码农,如果要写一个持有原生资源的类,有三种写法:把资源释放放到 __del__里,在引用计数归零时自动触发
还是放到close函数里,供finally手动调用
放到__exit__里,供with 触发
这就是说好的one way to do it?
在 Python 中,创建函数有两种方式:
def f(a):
return a * 2
f = lambda a: a * 2
def和lambda这两个关键字是不是有点重复了?
相比之下,JavaScript是这样的:
function f(a) {
return a * 2
}
var f = function(a) {
return a * 2
}
两种用法都是同一个关键字function。(说句题外话:虽然function关键字本身的一致性还可以,但JavaScript的this太坑,需要额外发明箭头符号来绕开this坑)
再比如说generator功能,你可以这样写:
def gen():
return (x * 2 for x in range(10))
也可以写
def gen():
for x in range(10):
yield x * 2
说好的one way to do it呢?
更奇葩的是把list和generator用在一起的情形:
>>> [i * 2 for i in range(5)] # 直接用方括号,得到list,里面装了五个数
[0, 2, 4, 6, 8]
>>> [(i * 2 for i in range(5))] # 在方括号里额外加入圆括号,得到list,里面装了一个generator
[ at 0x1078020f8>]
>>> list(i * 2 for i in range(5)) # 调用list(),得到list,里面装了五个数
[0, 2, 4, 6, 8]
>>> list((i * 2 for i in range(5))) # 调用list()时额外加入圆括号,得到的还是list,里面还是装了五个数
[0, 2, 4, 6, 8]
再看看PEP 20:There should be one-- and preferably only one --obvious way to do it.