Thursday, January 12, 2012

Python 不常见的实用技巧

在stackoverflow上看到有人讨论一些python的hidden feature,发现其中有几个确实还是蛮实用的。
特此摘了几个,翻译过来。

原文见http://stackoverflow.com/questions/101268/hidden-features-of-python

1 参数解包(argument unpacking)
传递list、tuple或dict对象给函数,用*或者**(字典),会自动将容器解开。例如
def show(a,b):
    print a,b
L=[1,2]

show(*L)

2 链比较
python支持链比较,例如
1<a<2

3 Decorator
通过@符号自动将一个函数封装起来,作为参数传递给另一个函数直接使用。类似宏的概念。例如

def func2(fun):
      def new_func1():
          do_sth...
          fun()
     return new_func1
@func2
def func1():
     do_sth...
在这个例子中,func1被传给func2,然后被func2的结果替换掉(即执行的是func2中的new_func1)。

4 Property
指定在某些对属性进行操作时候的触发函数,包括设置、读取和删除属性等。
property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
例如
class C(object):
    def getx(self): return self.__x
    def setx(self, value): self.__x = value
    def delx(self): del self.__x
    x = property(getx, setx, delx, "I'm the 'x' property.")

5 字典的get()函数
dict类型有get()函数,跟直接用索引值取值基本用法一致,但存在如下区别,在某些时候用get()会方便。
当key不存在的时候,用索引会导致异常退出;而get则会返回None,还可已给定一个失败时的默认值。
例如
sum[value] = sum.get(value,0) + 1

6 doctest模块
该模块会自动读取各个函数doc中的命令和对应执行结果,自动化进行用例测试。例如
def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    If the result is small enough to fit in an int, return an int.
    Else return a long.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result

def _test():
    import doctest
    doctest.testmod()    

if __name__ == "__main__":
    _test()

7 省略号(Ellipsis)
一般用于高维数组中的切片,用省略号的维上表示全部。
例如
a=array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12],
       [13, 14, 15, 16]])
a[...,2]
等价于a[:,2]

8 Enumerate 
封装可迭代类型,每个元素对应到index。例如
>>> 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

9 for else结构
for中测试的循环正常结束后执行else。除非之前执行了break,则不执行else。例如
for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

10 iter
iter(callable, until_value)迭代调用callable,生成迭代器,一直到until_value被callable返回。

11 字典格式自动输出解析
 >>>print("The {foo} is {bar}".format(foo='answer', bar=42))
The answer is 42.

12 with语法
with open('foo.txt', 'w') as f:
    f.write('hello!')