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

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

快速链接到答案:

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


当前回答

一切事物的一等性(“一切事物都是一个物体”),以及这可能造成的混乱。

>>> x = 5
>>> y = 10
>>> 
>>> def sq(x):
...   return x * x
... 
>>> def plus(x):
...   return x + x
... 
>>> (sq,plus)[y>x](y)
20

最后一行创建一个包含这两个函数的元组,然后计算y>x (True)并将其作为元组的索引(通过将其强制转换为int类型,1),然后使用参数y调用该函数并显示结果。

对于进一步的滥用,如果你返回一个带索引的对象(例如一个列表),你可以在末尾添加更多的方括号;如果内容是可调用的,更多的括号,等等。为了更变态,使用这样的代码的结果作为另一个例子中的表达式(即用下面的代码替换y>x):

(sq,plus)[y>x](y)[4](x)

这展示了Python的两个方面——极端的“一切都是一个对象”哲学,以及不恰当或考虑不良的语言语法使用方法,可能导致完全不可读、不可维护的意大利面条代码,适合一个表达式。

其他回答

可读正则表达式

在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})$"

使用and和or来模拟第三运算符。

python中的and和or操作符返回对象本身,而不是布尔值。因此:

In [18]: a = True

In [19]: a and 3 or 4
Out[19]: 3

In [20]: a = False

In [21]: a and 3 or 4
Out[21]: 4

然而,Py 2.5似乎添加了一个显式的第三运算符

    In [22]: a = 5 if True else '6'

    In [23]: a
    Out[23]: 5

好吧,如果你确定你的true子句的结果不是False,这是可行的。例子:

>>> def foo(): 
...     print "foo"
...     return 0
...
>>> def bar(): 
...     print "bar"
...     return 1
...
>>> 1 and foo() or bar()
foo
bar
1

要做到这一点,你还需要多做一点:

>>> (1 and [foo()] or [bar()])[0]
foo
0

然而,这并不漂亮。如果你的python版本支持它,请使用条件操作符。

>>> foo() if True or bar()
foo
0

Python的位置和关键字展开可以动态使用,而不仅仅是从存储的列表中使用。

l=lambda x,y,z:x+y+z
a=1,2,3
print l(*a)
print l(*[a[0],2,3])

它通常在以下情况下更有用:

a=[2,3]
l(*(a+[3]))

使用负step反转可迭代对象

>>> s = "Hello World"
>>> s[::-1]
'dlroW olleH'
>>> a = (1,2,3,4,5,6)
>>> a[::-1]
(6, 5, 4, 3, 2, 1)
>>> a = [5,4,3,2,1]
>>> a[::-1]
[1, 2, 3, 4, 5]

如果你在你的应用程序中重命名了一个类,你正在通过Pickle加载用户保存的文件,而其中一个重命名的类存储在用户的旧保存中,你将不能加载这个Pickle文件。

然而,只要在你的类定义中添加一个引用,一切就好了:

例如,:

class Bleh:
    pass

现在,

class Blah:
    pass

所以,你的用户的pickle保存的文件包含一个Bleh的引用,它不存在,由于重命名。这是固定的吗?

Bleh = Blah

简单!