Python中的隐藏特点

November 25, 2014

Reading time ~4 minutes

前言

  该篇文章是来自于stackoverflow上的一个问题,原文地址,个人觉得很不错,就将它翻译了过来。可能有些单词翻译的不太准确,欢迎矫正。

运算符的链式比较

Example:
    >>> x = 5
    >>> 1 < x < 10
    True
    >>> 10 < x < 20 
    False
    >>> x < 10 < x*10 < 100
    True
    >>> 10 > x <= 9
    True
    >>> 5 == x > 4
    True

  在这个例子中,你可能认为首先运算 1<x,得到结果为 True ,接着运算 True < 10 ,得到结果为 True .但是,事实并非如此,看最后一个表达式计算,你就知道并非这样,比如第一个表达式,他其实是转化成了 1<x and x < 10 .第二个表达式转化成了 x<10 and 10<x10 and x10<100 ,为了更少的打印,每个表达式只计算了一次(告诉你,自己玩吧)。评论里有提到,lisp也是这种类似的机制。

函数参数解包

  使用***作 为函数参数时,你可以传入list和dict类型数据,意思就是当你使用 * 前缀时可以代表list,tuple等序列数据,而 ** 前缀可以表示字典类型数据。 例子:

def draw_point(x, y):
        # do some magic

        point_foo = (3, 4)
        point_bar = {'y': 3, 'x': 2}

        draw_point(*point_foo)
        draw_point(**point_bar)

字典、列表被广泛用于容器后,非常方便。

就地交换

for example:
    >>> a = 10
    >>> b = 5
    >>> a, b
    (10, 5)

    >>> a, b = b, a
    >>> a, b
    (5, 10)

这个指令(a,b = b,a)右边的表达式创建了一个新元组,左边的立马解包到变量a,b。在这条指令过后,a,b的值已经被交换,而 a,b这个新元祖也未被GC标记和引用,所以未被回收。

for…else语句

  

for i in foo:
        if i == 0:
            break
    else:
        print('i was never zero.)

这个程序在 break 没有被调用的时候会执行,这段代码还可以使用下面这段通俗代码来理解:

found = False
    for i in foo:
        if i == 0:
            found = True
            break
    if not found:
        print('i was never zero.')

不过这个特点还是少用比较好,放在for循环内部就可以了,放在外部有可能和其他的if语句引起bug.

指定名字的格式化

%可以像字典一样对参数进行格式化:

for example:
    >>> print "The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42}
    The answer is 42.

    >>> foo, bar = 'question', 123

    >>> print "The %(foo)s is %(bar)i." % locals()
    The question is 123.

locals()也是字典,你可以使用locals()% 替换本地变量。

新风格的格式化:

>>> print("The {foo} is {bar}".format(foo='answer', bar=42))

推荐新风格,新风格跟有pythonic的感觉。

使用.pth文件添加路径

  添加python包路径的最好办法是使用.pth文件进行添加路径,每一行只能包含一条路径,这些路径会添加到sys.path中,而且安装的目录不会覆盖原来的标准模块,这个机制意味着你不能安装标准模块的固定版本(因为都会存在).

set内置的操作符重载

  集合类型内置了许多操作符号的重载,比如 & , | 等。

for example:
        >>> a = set([1,2,3,4])
        >>> b = set([3,4,5,6])
        >>> a | b # Union
        {1, 2, 3, 4, 5, 6}
        >>> a & b # Intersection
        {3, 4}
        >>> a < b # Subset
        False
        >>> a - b # Difference
        {1, 2}
        >>> a ^ b # Symmetric Difference
        {1, 2, 5, 6}

嵌套的列表表达式和生成表达式

for example:
    [(i,j) for i in range(3) for j in range(i) ]    
    ((i,j) for i in range(4) for j in range(i) )

  python的列表表达式可以生成一个值的列表,这个好理解,而生成表达式是会产生一系列的表达式,举个例子,比如 square = (i2+2 for i in 3),最终会生成(02+2),(12+2),(22+2),生成表达式的思想就是协程的yield/resume机制。关于协程的概念,戳这里。对于生成器的优点就是 他不会产生中间存储值,相对于列表表达式使用更少的内存,而列表是一次生成存储之后再使用,在某些情况下,列表表达式相对于生成器表达式速度更快。在循环中,你可以使用一个生成器替换许多嵌套:

for example:
        >>> n = ((a,b) for a in range(0,2) for b in range(4,6))
        >>> for i in n:
        ...   print i 

        (0, 4)
        (0, 5)
        (1, 4)
        (1, 5)

枚举计算

  通过枚举包装一个迭代器,他将会产生和索引一起的元素。

for example:
        >>> a = ['a', 'b', 'c', 'd', 'e']
        >>> for index, item in enumerate(a): 
                print index, item
        ...
        0 a
        1 b
        2 c
        3 d
        4 e

同时,枚举还可以指定开始位置.

for example:
        for index,item in enumerate(a, start=2)

iter()能够携带一个可调用的参数

for instance:
        def seek_next_line(f):
        for c in iter(lambda : f.read(1),"\n"):
            pass

iter是一个迭代器,iter(callable, sentinel),被理解为被调用的参数是在哨兵被返回时调用。


  未完待续。