False values
这些都是false value:None
, False
,
0
, []
, {}
,
''
。判断empty的应用场景可能多些,如果像Ruby那样只让nil
和false
为false就好了。
Trailing colons
1 | if True: |
写成这样如何?
1 | if True |
Single/double quotes
Python不区分单/双引号,失去了string interpolation的好处,另外就是需要尽可能少escape字符时也带来了麻烦,当然可以用triple-quoted string和raw string来代替,但毕竟繁琐了些。Raw string的设计还能接受,但为什么不引入这个:
1 | %w(zero one two three) |
dunder
__len__
: 为什么使用len(obj)
而不是def len():
和obj.len()
呢?__mul__
:def *(self, rhs):
会更清晰些吧
类名
随处可见的lowercase的标准库类名和函数名。
- CamelCase:
collections.OrderedDict
。 - nocase:
collections.defaultdict
,collections.namedtuple
map/filter/zip
- 产生序列的:
map|filter|zip
- 产生iterator的:
itertools.i(map|filter|zip)
为什么对于list
和iterator
要有两套功能相近的函数呢?如果把map
设计成这样:参数为list
就返回list
,参数为iterator
就返回iterator
。这样就不需要另成一套的itertools.i(map|filter|zip)
了。
Context manager和with statement
with
可能借鉴自Lisp的with-*
macro,实现的功能是wrap一段代码,在其执行前后执行自定义的操作。功能和这个Haskell函数类似:
1 | bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c |
我一直觉得这个feature是不值得成为关键字的。如果改造一下变成Smalltalk/Ruby的block那种形式会好很多。比如如下Ruby风格的代码:
1 | def pre(): |
再注意__exit__
的类型签名:
1 | def __exit__(self, type, value, traceback): |
后三个参数都是用来表示异常的,异常是不是special enough以至于可以break the rules了?
One-expression lambda
因为Python强制的off-side rule,超过一个表达式的语法确实很难设计。我想到的是Ruby风格的block。
List comprehensions
体现语言表达能力的结构,不过顺序和习惯有些差异:先写出操作,后写出执行操作的对象。Smalltalk/Ruby风格的cascading加上block可能更自然些:
1 | (1..100).select {|x| x % 3 == 0 }.reverse |
1 | list(reversed([x for x in range(1,101) if x % 3 == 0])) |
如果Python能采用Haskell的简约写法也不错:
1 | reverse [x | x <- [1..100], x `mod` 3 == 0] |
yield
Python的yield
用于实现iterator
,给callee提供值。如果像Ruby那样,yield
的作用是调用一个callback会更加灵活一些。
幸好有PEP
342把yield
改成双向的了,实现了coroutine,可以实现一些比较强大(花哨)的结构如Monad。
后记
Python设计很丑陋,但是还得用。scapy、scrapy、scipy、matplotlib、pil都是以后打算了解的东西,而它们都没有成熟的同等功能的Ruby替代品。