Python is ugly

False values

这些都是false value:None, False, 0, [], {}, ''。判断empty的应用场景可能多些,如果像Ruby那样只让nilfalse为false就好了。

Trailing colons

1
2
if True:
print 'hello'

写成这样如何?

1
2
if True
print 'hello'

Single/double quotes

Python不区分单/双引号,失去了string interpolation的好处,另外就是需要尽可能少escape字符时也带来了麻烦,当然可以用triple-quoted string和raw string来代替,但毕竟繁琐了些。Raw string的设计还能接受,但为什么不引入这个:

1
2
%w(zero one two three)
=> ["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)

为什么对于listiterator要有两套功能相近的函数呢?如果把map设计成这样:参数为list就返回list,参数为iterator就返回iterator。这样就不需要另成一套的itertools.i(map|filter|zip)了。

Context manager和with statement

with可能借鉴自Lisp的with-* macro,实现的功能是wrap一段代码,在其执行前后执行自定义的操作。功能和这个Haskell函数类似:

1
2
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
-- Defined in `Control.Exception.Base

我一直觉得这个feature是不值得成为关键字的。如果改造一下变成Smalltalk/Ruby的block那种形式会好很多。比如如下Ruby风格的代码:

1
2
3
4
5
6
7
8
def pre():
print('hello')

def post():
print('world')

with pre, post do
print(', ')

再注意__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替代品。