Python编程语言中有哪些鲜为人知但很有用的特性?

尽量将答案限制在Python核心。 每个回答一个特征。 给出一个例子和功能的简短描述,而不仅仅是文档链接。 使用标题作为第一行标记该特性。

快速链接到答案:

参数解包 牙套 链接比较运算符 修饰符 可变默认参数的陷阱/危险 描述符 字典默认的.get值 所以测试 省略切片语法 枚举 其他/ 函数作为iter()参数 生成器表达式 导入该 就地值交换 步进列表 __missing__物品 多行正则表达式 命名字符串格式化 嵌套的列表/生成器推导 运行时的新类型 .pth文件 ROT13编码 正则表达式调试 发送到发电机 交互式解释器中的制表符补全 三元表达式 试着/ / else除外 拆包+打印()函数 与声明


当前回答

切片为左值。这个埃拉托色尼筛子产生一个素数或0的列表。元素会随着循环中的切片分配而被0掉。

def eras(n):
    last = n + 1
    sieve = [0,0] + list(range(2, last))
    sqn = int(round(n ** 0.5))
    it = (i for i in xrange(2, sqn + 1) if sieve[i])
    for i in it:
        sieve[i*i:last:i] = [0] * (n//i - i + 1)
    return filter(None, sieve)

为了工作,左边的切片必须在右边分配一个相同长度的列表。

其他回答

可读正则表达式

在Python中,您可以将正则表达式拆分为多行,命名匹配并插入注释。

示例详细语法(来自Python):

>>> pattern = """
... ^                   # beginning of string
... M{0,4}              # thousands - 0 to 4 M's
... (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                     #            or 500-800 (D, followed by 0 to 3 C's)
... (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                     #        or 50-80 (L, followed by 0 to 3 X's)
... (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                     #        or 5-8 (V, followed by 0 to 3 I's)
... $                   # end of string
... """
>>> re.search(pattern, 'M', re.VERBOSE)

命名匹配示例(摘自正则表达式HOWTO)

>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'

由于字符串字面值的串联,你也可以在不使用re.VERBOSE的情况下详细地编写一个正则表达式。

>>> pattern = (
...     "^"                 # beginning of string
...     "M{0,4}"            # thousands - 0 to 4 M's
...     "(CM|CD|D?C{0,3})"  # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                         #            or 500-800 (D, followed by 0 to 3 C's)
...     "(XC|XL|L?X{0,3})"  # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                         #        or 50-80 (L, followed by 0 to 3 X's)
...     "(IX|IV|V?I{0,3})"  # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                         #        or 5-8 (V, followed by 0 to 3 I's)
...     "$"                 # end of string
... )
>>> print pattern
"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"

元组在for循环、列表推导式和生成器表达式中的解包:

>>> l=[(1,2),(3,4)]
>>> [a+b for a,b in l ] 
[3,7]

在这个习语中,用于迭代字典中的(键,数据)对:

d = { 'x':'y', 'f':'e'}
for name, value in d.items():  # one can also use iteritems()
   print "name:%s, value:%s" % (name,value)

打印:

name:x, value:y
name:f, value:e

插入与追加

不是特稿,但可能会很有趣

假设您想要在列表中插入一些数据,然后反转它。最简单的方法是

count = 10 ** 5
nums = []
for x in range(count):
    nums.append(x)
nums.reverse()

然后你会想:把数字从最开始插入怎么样?所以:

count = 10 ** 5 
nums = [] 
for x in range(count):
    nums.insert(0, x)

但它却慢了100倍!如果我们设置count = 10 ** 6,它将慢1000倍;这是因为插入是O(n²),而追加是O(n)。

造成这种差异的原因是insert每次调用时都必须移动列表中的每个元素;Append只是在列表的末尾添加元素(有时它必须重新分配所有元素,但它仍然更快)

如果你不喜欢使用空格来表示作用域,你可以通过发出以下命令来使用c风格{}:

from __future__ import braces

函数参数解包

可以使用*和**将列表或字典解包为函数参数。

例如:

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)

非常有用的快捷方式,因为列表、元组和字典被广泛用作容器。