Python的隐藏特征

Hidden features of Python

什么是Python编程语言中鲜为人知但有用的特性?

  • 尝试限制对python核心的答案。
  • 每个答案一个功能。
  • 给出该特性的一个示例和简短描述,而不仅仅是指向文档的链接。
  • 使用标题作为第一行标记功能。

快速链接到答案:

  • 参数解包
  • 支撑
  • 链接比较运算符
  • 装饰者
  • 默认参数gotchas/可变默认参数的危险
  • 描述符
  • 字典默认.get
  • 文档串测试
  • 省略号切片语法
  • 枚举
  • 为/其他
  • 函数作为iter()参数
  • 生成器表达式
  • import this
  • 就地值交换
  • 列表步进
  • __missing__
  • 多行正则表达式
  • 命名字符串格式
  • 嵌套列表/生成器理解
  • 运行时的新类型
  • .pth文件
  • ROT13编码
  • 正则表达式调试
  • 发送到发电机
  • 交互式解释器中的制表符完成
  • 三元表达式
  • try/except/else
  • 解包+print()功能
  • with报表

链接比较运算符:

1
2
3
4
5
6
7
8
9
10
11
>>> 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 < 10x < 10 and 10 < x * 10 and x*10 < 100,但是输入较少,每个术语只评估一次。


获取python regex解析树以调试regex。

正则表达式是Python的一个很好的特性,但是调试它们可能很麻烦,而且很容易出错。

幸运的是,python可以通过将未记录的、实验性的、隐藏的标志re.DEBUG(实际上是128)传递给re.compile来打印regex解析树。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
    re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
  subpattern None
    literal 61
    subpattern 1
      in
        literal 45
        literal 43
      max_repeat 1 2
        in
          range (48, 57)
literal 93
subpattern 2
  min_repeat 0 65535
    any None
in
  literal 47
  literal 102
  literal 111
  literal 110
  literal 116

一旦理解了语法,就可以发现错误。在那里,我们可以看到我忘记了在[/font]中逃离[]

当然,您可以将它与您想要的任何标志结合起来,例如注释的regex:

1
2
3
4
5
6
7
8
9
10
>>> re.compile("""
 ^              # start of a line
 \[font         # the font tag
 (?:=(?P<size>  # optional [font=+size]
 [-+][0-9]{1,2} # size specification
 ))?
 \]             # end of tag
 (.*?)          # text between the tags
 \[/font\]      # end of the tag
"""
, re.DEBUG|re.VERBOSE|re.DOTALL)

使用enumerate

在一个使用enumerate包可迭代变量和它想随着ITS项目收益的指标。

例如:

1
2
3
4
5
6
7
8
9
>>> 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
>>>

参考文献:

  • Python教程循环技术
  • Python文档的enumerate内置函数
  • PEP 279

创建生成器对象

如果你写

1
x=(n for n in foo if bar(n))

你可以拿出发电机,把它分配给X。现在它意味着你可以

1
for n in x:

这样做的好处是,您不需要中间存储,如果需要的话,就需要中间存储。

1
x = [n for n in foo if bar(n)]

在某些情况下,这会导致显著的加速。

您可以将许多if语句附加到生成器的末尾,基本上复制嵌套for循环:

1
2
3
4
5
6
7
8
>>> 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)


iter()不能接受可调用参数

例如:

1
2
3
4
def seek_next_line(f):
    for c in iter(lambda: f.read(1),'
'
):
        pass

iter(callable, until_value)函数反复调用callable并生成其结果,直到返回until_value为止。


注意可变的默认参数

1
2
3
4
5
6
7
8
9
10
>>> def foo(x=[]):
...     x.append(1)
...     print x
...
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

相反,您应该使用表示"未给定"的sentinel值,并将其替换为默认的可变值:

1
2
3
4
5
6
7
8
9
>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

向生成器函数发送值。例如,具有此功能:

1
2
3
4
5
6
7
def mygen():
   """Yield 5 until something else is passed back via send()"""
    a = 5
    while True:
        f = (yield a) #yield a and possibly get f in return
        if f is not None:
            a = f  #store the new value

你可以:

1
2
3
4
5
6
7
8
9
>>> g = mygen()
>>> g.next()
5
>>> g.next()
5
>>> g.send(7)  #we send this back to the generator
7
>>> g.next() #now it will yield 7 until we send something else
7


如果您不喜欢使用空格来表示范围,可以使用C样式,方法是发出:

1
from __future__ import braces


slice运算符中的step参数。例如:

1
2
3
a = [1,2,3,4,5]
>>> a[::2]  # iterate over the whole list in 2-increments
[1,3,5]

特例x[::-1]是"x revered"的一个有用的习语。

1
2
>>> a[::-1]
[5,4,3,2,1]


装饰者

修饰符允许将一个函数或方法包装在另一个函数中,该函数或方法可以添加功能、修改参数或结果等。您可以在函数定义的上方一行编写修饰符,从"at"符号(@)开始。

示例显示了一个print_args修饰器,它在调用该修饰函数之前打印该修饰函数的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> def print_args(function):
>>>     def wrapper(*args, **kwargs):
>>>         print 'Arguments:', args, kwargs
>>>         return function(*args, **kwargs)
>>>     return wrapper

>>> @print_args
>>> def write(text):
>>>     print text

>>> write('foo')
Arguments: ('foo',) {}
foo


在else for语法(http://docs.python.org湖/编号/ for.html)

1
2
3
4
5
for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

"else"块都将执行最后的一环,除非是被打破。

上面的代码可以被仿真为如下:

1
2
3
4
5
6
7
found = False
for i in foo:
    if i == 0:
        found = True
        break
if not found:
    print("i was never 0")

从2.5开始,dicts有一个特殊的方法__missing__,用于缺少的项目:

1
2
3
4
5
6
7
8
9
10
>>> class MyDict(dict):
...  def __missing__(self, key):
...   self[key] = rv = []
...   return rv
...
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

collections中还有一个dict子类,称为defaultdict,其作用几乎相同,但对不存在的项调用了一个没有参数的函数:

1
2
3
4
5
6
>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

我建议在将此类dict传递给不需要此类子类的函数之前,先将其转换为常规dict。许多代码使用d[a_key]并捕获keyErrors来检查是否存在一个可以向dict添加新项的项。


就地值交换

1
2
3
4
5
6
7
8
>>> a = 10
>>> b = 5
>>> a, b
(10, 5)

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

赋值的右侧是一个创建新元组的表达式。任务的左侧立即将(未引用的)元组解包到名称ab中。

赋值后,新的元组未被引用并标记为垃圾收集,绑定到ab的值已被交换。

如数据结构的python教程部分所述,

Note that multiple assignment is really just a combination of tuple packing and sequence unpacking.


可读的正则表达式

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

示例详细语法(从深入到python):

1
2
3
4
5
6
7
8
9
10
11
12
>>> 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)

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

由于字符串文字串联,您还可以在不使用re.VERBOSE的情况下口头编写regex。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> 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})$"


函数参数解箱

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

例如:

1
2
3
4
5
6
7
8
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)

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


当您在代码文件顶部使用正确的编码声明时,rot13是源代码的有效编码:

1
2
3
4
#!/usr/bin/env python
# -*- coding: rot13 -*-

cevag"Uryyb fgnpxbiresybj!".rapbqr("rot13")

以完全动态的方式创建新类型

1
2
3
4
5
>>> NewType = type("NewType", (object,), {"x":"hello
<hr><P>上下文管理器和"
<wyn>with</wyn>声明"</P><P>在PEP343中引入的上下文管理器是一个对象,用作一组语句的运行时上下文。</P><P>由于该特性使用了新的关键字,因此逐渐引入:它通过<wyn>__future__</wyn>指令在python 2.5中可用。默认情况下,python 2.6及更高版本(包括python 3)具有可用性。</P><P>我经常使用"with"语句,因为我认为它是一个非常有用的结构,下面是一个快速演示:</P>[cc lang="python"]from __future__ import with_statement

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

在幕后发生的是,"with"语句调用文件对象上的特殊__enter____exit__方法。如果从WITH语句体中引发了任何异常,也会将异常详细信息传递给__exit__,从而允许在那里进行异常处理。

在这种特殊情况下,这对您的作用是,它保证在执行超出with套件的范围时关闭文件,无论执行是否正常或是否引发异常。它基本上是一种抽象掉常见异常处理代码的方法。

其他常见的用例包括使用线程和数据库事务进行锁定。


字典有get()方法

字典有一个"get()"方法。如果你做了d[‘key’]但key不在,你会得到一个例外。如果你做了d.get("key"),如果没有"key",你就什么也得不到。可以添加第二个参数以返回该项,而不是不返回任何项,例如:d.get("key",0)。

它非常适用于数字相加:

sum[value] = sum.get(value, 0) + 1


描述符

它们是一系列核心python特性背后的魔力。

当使用点式访问查找成员(例如x.y)时,python首先在实例字典中查找该成员。如果找不到,它会在类字典中查找。如果它在类字典中找到它,并且对象实现了描述符协议,而不是仅仅返回它,那么Python将执行它。描述符是实现__get____set____delete__方法的任何类。

以下是使用描述符实现自己的(只读)属性版本的方法:

1
2
3
4
5
6
7
8
class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

您可以像使用内置属性()一样使用它:

1
2
3
4
class MyClass(object):
    @Property
    def foo(self):
        return"Foo!"

在Python中,描述符用于实现属性、绑定方法、静态方法、类方法和槽等等。理解它们很容易理解为什么以前看起来像Python"怪癖"的很多东西都是这样的。

RaymondHettinger有一个优秀的教程,它比我更好地描述它们。


条件分配

1
x = 3 if (y == 1) else 2

它到底是什么样的声音:"如果y是3至指定的X 1,X 2,否则分配到"。注意,这是没有必要的,但我的父母,他们为readability样。所以你可以链它如果你有更多的东西):

1
x = 3 if (y == 1) else 2 if (y == -1) else 1

虽然在某些点,它太远了一点。

注意你可以使用if…在任何其他的表达。例如:

1
(func1 if y == 1 else func2)(arg1, arg2)

我想如果是func1 1和y的函数,否则。在两个情况下相应的函数的参数要与arg1和arg2。

analogously,以下是有效的:

1
x = (class1 if y == 1 else class2)(arg1, arg2)

在Class1和Class2是两类。


doctest:同时进行文档和单元测试。

从python文档中提取的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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()


命名格式

%-格式化需要字典(还应用%i/%s等验证)。

1
2
3
4
5
6
7
>>> 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()也是一个字典,所以您可以简单地将其作为dict传递,并从本地变量中获得.%的子项。我认为这是不允许的,但可以简化事情。

新样式格式

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


为了添加更多的python模块(尤其是第三方模块),大多数人似乎使用pythonpath环境变量,或者在他们的站点包目录中添加符号链接或目录。另一种方法是使用*.pth文件。下面是python文档的官方解释:

"The most convenient way [to modify
python's search path] is to add a path
configuration file to a directory
that's already on Python's path,
usually to the .../site-packages/
directory. Path configuration files
have an extension of .pth, and each
line must contain a single path that
will be appended to sys.path. (Because
the new paths are appended to
sys.path, modules in the added
directories will not override standard
modules. This means you can't use this
mechanism for installing fixed
versions of standard modules.)"


异常else子句:

1
2
3
4
5
6
7
8
try:
  put_4000000000_volts_through_it(parrot)
except Voom:
  print"'E's pining!"
else:
  print"This parrot is no more!"
finally:
  end_sketch()

使用else子句比向try子句添加其他代码要好,因为它可以避免意外捕获一个没有被try保护的代码引发的异常…except语句。

请参阅http://docs.python.org/tut/node10.html


重新提出例外:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Python 2 syntax
try:
    some_operation()
except SomeError, e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

# Python 3 syntax
try:
    some_operation()
except SomeError as e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

错误处理程序中没有参数的"raise"语句告诉python在原始跟踪完整的情况下重新引发异常,允许您说"哦,对不起,对不起,我不是有意捕获它,对不起,对不起。"

如果您希望打印、存储或篡改原始的回溯,可以使用sys.exc_info()获取它,并像python使用"回溯"模块一样打印它。


主要消息:)

1
2
import this
# btw look at this module's source :)

解密码:

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!


交互式解释器选项卡完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
try:
    import readline
except ImportError:
    print"Unable to load readline module."
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")


>>> class myclass:
...    def function(self):
...       print"my function"
...
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__   class_instance.__module__
class_instance.__doc__     class_instance.function
>>> class_instance.f<TAB>unction()

您还必须设置pythonstartup环境变量。


set内置的运算符重载:

1
2
3
4
5
6
7
8
9
10
11
12
>>> 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}

标准库参考中的更多详细信息:集合类型


嵌套列表理解和生成器表达式:

1
2
[(i,j) for i in range(3) for j in range(i) ]    
((i,j) for i in range(4) for j in range(i) )

这些可以替换大量嵌套循环代码。


负轮

round()函数将浮点数舍入为以十进制数字表示的给定精度,但精度可以为负数:

1
2
3
4
>>> str(round(1234.5678, -2))
'1200.0'
>>> str(round(1234.5678, 2))
'1234.57'

注:round()总是返回一个float,上面例子中使用str()是因为浮点数学不精确,在2.x下,第二个例子可以打印为1234.5700000000001。另请参阅decimal模块。


乘以布尔值

我在Web开发中经常做的一件事是有选择地打印HTML参数。我们在其他语言中都看到过这样的代码:

1
class='<% isSelected ?"selected" :"" %>'

在python中,您可以用一个布尔值相乘,它完全按照您期望的那样做:

1
class='<%"selected" * isSelected %>'

这是因为乘法将布尔值强制为整数(0表示假,1表示真),在python中,用一个字符串乘以一个int会重复n次字符串。


python的高级切片操作有一个鲜为人知的语法元素,即省略号:

1
2
3
4
5
6
>>> class C(object):
...  def __getitem__(self, item):
...   return item
...
>>> C()[1:2, ..., 3]
(slice(1, 2, None), Ellipsis, 3)

不幸的是,它几乎没有用处,因为只有涉及到元组时才支持省略号。


重新调用函数!

每次有东西匹配正则表达式时都可以调用函数,这一事实非常方便。这里我有一个例子,用"嗨"替换每个"你好",用"弗雷德"替换"那里",等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import re

def Main(haystack):
  # List of from replacements, can be a regex
  finds = ('Hello', 'there', 'Bob')
  replaces = ('Hi,', 'Fred,', 'how are you?')

  def ReplaceFunction(matchobj):
    for found, rep in zip(matchobj.groups(), replaces):
      if found != None:
        return rep

    # log error
    return matchobj.group(0)

  named_groups = [ '(%s)' % find for find in finds ]
  ret = re.sub('|'.join(named_groups), ReplaceFunction, haystack)
  print ret

if __name__ == '__main__':
  str = 'Hello there Bob'
  Main(str)
  # Prints 'Hi, Fred, how are you?'


在python 3中解包tuple

在Python3中,可以使用与函数定义中可选参数相同的语法来解包元组:

1
2
3
4
5
6
7
>>> first,second,*rest = (1,2,3,4,5,6,7,8)
>>> first
1
>>> second
2
>>> rest
[3, 4, 5, 6, 7, 8]

但是,一个不太知名、功能更强大的特性允许您在列表中间包含未知数量的元素:

1
2
3
4
5
6
7
>>> first,*rest,last = (1,2,3,4,5,6,7,8)
>>> first
1
>>> rest
[2, 3, 4, 5, 6, 7]
>>> last
8


多行字符串

一种方法是使用反斜杠:

1
2
3
4
>>> sql ="select * from some_table \
where id > 10"

>>> print sql
select * from some_table where id > 10

另一种方法是使用三重引号:

1
2
3
4
>>> sql ="""select * from some_table
where id > 10"""

>>> print sql
select * from some_table where id > 10

问题在于它们没有缩进(代码中看起来很糟糕)。如果你试图缩进,它只会打印出你输入的空白。

我最近发现的第三个解决方案是将字符串分成行并用括号括起来:

1
2
3
4
5
>>> sql = ("select * from some_table" # <-- no comma, whitespace at end
          "where id > 10"
          "order by name")
>>> print sql
select * from some_table where id > 10 order by name

注意行与行之间没有逗号(这不是元组),并且必须考虑到字符串所需的任何尾随/前导空格。顺便说一下,所有这些都是与占位符一起工作的(比如"my name is %s" % name)。


根据许多人的要求,这个答案已经被转移到问题本身。


  • 它包含一个下划线,显示最新的输出值(由解释器在交互式会话):
1
2
3
4
5
>>> (a for a in xrange(10000))
<generator object at 0x81a8fcc>
>>> b = 'blah'
>>> _
<generator object at 0x81a8fcc>
  • 控制器:一个方便的Web浏览器
1
2
>>> import webbrowser
>>> webbrowser.open_new_tab('http://www.stackoverflow.com')
  • a内置的HTTP服务器。在当前的文件到服务目录:
1
python -m SimpleHTTPServer 8000
  • atexit
1
>>> import atexit


pow()还可以有效地计算(x**y)%z。

对于内置的pow()函数,有一个鲜为人知的第三个参数,它允许您比简单地执行(x ** y) % z更有效地计算xy模z:

1
2
3
>>> x, y, z = 1234567890, 2345678901, 17
>>> pow(x, y, z)            # almost instantaneous
6

相比之下,(x ** y) % z在我的机器上一分钟内没有给出相同值的结果。


您可以用zip轻松地转换数组。

1
2
3
a = [(1,2), (3,4), (5,6)]
zip(*a)
# [(1, 3, 5), (2, 4, 6)]

用不同的起始索引枚举

这个答案部分涵盖了enumerate,但最近我发现了enumerate的一个更隐蔽的特征,我认为它应该有自己的帖子,而不仅仅是一个评论。

由于python 2.6,您可以在其第二个参数中为enumerate指定一个起始索引:

1
2
3
4
5
>>> l = ["spam","ham","eggs"]
>>> list(enumerate(l))
>>> [(0,"spam"), (1,"ham"), (2,"eggs")]
>>> list(enumerate(l, 1))
>>> [(1,"spam"), (2,"ham"), (3,"eggs")]

我发现它非常有用的一个地方是,当我枚举对称矩阵的条目时。由于矩阵是对称的,所以我只需迭代上三角就可以节省时间,但在这种情况下,我必须在内部for循环中使用具有不同起始索引的enumerate,以正确跟踪行和列索引:

1
2
3
for ri, row in enumerate(matrix):
    for ci, column in enumerate(matrix[ri:], ri):
        # ci now refers to the proper column index

奇怪的是,enumerate的这种行为没有记录在help(enumerate)中,只记录在在线文档中。


可以使用属性使类接口更严格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class C(object):
    def __init__(self, foo, bar):
        self.foo = foo # read-write property
        self.bar = bar # simple attribute

    def _set_foo(self, value):
        self._foo = value

    def _get_foo(self):
        return self._foo

    def _del_foo(self):
        del self._foo

    # any of fget, fset, fdel and doc are optional,
    # so you can make a write-only and/or delete-only property.
    foo = property(fget = _get_foo, fset = _set_foo,
                   fdel = _del_foo, doc = 'Hello, I am foo!')

class D(C):
    def _get_foo(self):
        return self._foo * 2

    def _set_foo(self, value):
        self._foo = value / 2

    foo = property(fget = _get_foo, fset = _set_foo,
                   fdel = C.foo.fdel, doc = C.foo.__doc__)

在python 2.6和3.0中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class C(object):
    def __init__(self, foo, bar):
        self.foo = foo # read-write property
        self.bar = bar # simple attribute

    @property
    def foo(self):
        '''Hello, I am foo!'''

        return self._foo

    @foo.setter
    def foo(self, value):
        self._foo = value

    @foo.deleter
    def foo(self):
        del self._foo

class D(C):
    @C.foo.getter
    def foo(self):
        return self._foo * 2

    @foo.setter
    def foo(self, value):
        self._foo = value / 2

要了解属性如何工作的更多信息,请参阅描述符。


许多人不知道"你"的功能。这是一个伟大的方式找到什么对象可以从解释器。例如,如果你想看到一个列表的所有字符串的方法:

1
2
3
>>> dir("foo")
['__add__', '__class__', '__contains__', (snipped a bunch), 'title',
 'translate', 'upper', 'zfill']

然后,如果你想要更多的信息关于一个特定的方法,你可以调用它的"帮助"。

1
2
3
4
5
6
7
>>> help("foo".upper)
    Help on built-in function upper:

upper(...)
    S.upper() -> string

    Return a copy of the string S converted to uppercase.


设置/冻结

可能一个容易被忽视的python内置组件是"set/frozenset"。

当您有这样的列表时很有用,[1,2,1,1,2,3,4]并且只需要这样的唯一性[1,2,3,4]。

使用set()可以得到:

1
2
3
4
5
6
7
8
9
10
11
12
>>> x = [1,2,1,1,2,3,4]
>>>
>>> set(x)
set([1, 2, 3, 4])
>>>
>>> for i in set(x):
...     print i
...
1
2
3
4

当然,要在列表中获得唯一的数量:

1
2
>>> len(set([1,2,1,1,2,3,4]))
4

还可以使用set().is subset()查找列表是否是其他列表的子集:

1
2
>>> set([1,2,3,4]).issubset([0,1,2,3,4,5])
True

从python 2.7和3.0开始,可以使用大括号创建集合:

1
myset = {1,2,3,4}

以及集合理解:

1
{x for x in stuff}

有关详细信息:http://docs.python.org/library/stdtypes.html设置


内置base64、zlib和rot13编解码器

字符串有encodedecode方法。通常用于将str转换为unicode,反之亦然,例如使用u = s.encode('utf8')。但是还有其他一些方便的内置编解码器。可以使用zlib(和bz2)进行压缩和解压缩,而无需显式导入:

1
2
3
>>> s = 'a' * 100
>>> s.encode('zlib')
'x\x9cKL\xa4=\x00\x00zG%\xe5'

同样,您可以对base64进行编码和解码:

1
2
3
4
5
6
>>> 'Hello world'.encode('base64')
'SGVsbG8gd29ybGQ=
'

>>> 'SGVsbG8gd29ybGQ=
'
.decode('base64')
'Hello world'

当然,您也可以选择13:

1
2
>>> 'Secret message'.encode('rot13')
'Frperg zrffntr'


口译员中的口译员

标准库的代码模块允许您在程序中包含自己的read eval打印循环,或者运行一个完整的嵌套解释器。例如(从这里复制了我的示例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ python
Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type"help","copyright","credits" or"license" for more information.
>>> shared_var ="Set in main console"
>>> import code
>>> ic = code.InteractiveConsole({ 'shared_var': shared_var })
>>> try:
...     ic.interact("My custom console banner!")
... except SystemExit, e:
...     print"Got SystemExit!"
...
My custom console banner!
>>> shared_var
'Set in main console'
>>> shared_var ="Set in sub-console"
>>> import sys
>>> sys.exit()
Got SystemExit!
>>> shared_var
'Set in main console'

这对于您希望接受来自用户的脚本化输入或实时查询虚拟机状态的情况非常有用。

TurboGears使用一个Webconsole,从中您可以查询您的实时Web应用程序的状态,从而达到了非常好的效果。


1
2
3
4
5
6
>>> from functools import partial
>>> bound_func = partial(range, 0, 10)
>>> bound_func()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> bound_func(2)
[0, 2, 4, 6, 8]

不是真正的隐藏功能,但部分功能对于功能的后期评估非常有用。

可以根据需要将初始调用中的任意多个或任意少个参数绑定到分部,并在以后使用任何剩余参数调用它(在本例中,我将begin/end参数绑定到range,但第二次使用step参数调用它)。

请参阅文档。


在调试复杂数据结构时,pprint模块非常方便。

从文件中引用。

1
2
3
4
5
6
7
8
9
10
11
>>> import pprint    
>>> stuff = sys.path[:]
>>> stuff.insert(0, stuff)
>>> pprint.pprint(stuff)
[<Recursion on list with id=869440>,
 '',
 '/usr/local/lib/python1.5',
 '/usr/local/lib/python1.5/test',
 '/usr/local/lib/python1.5/sunos5',
 '/usr/local/lib/python1.5/sharedmodules',
 '/usr/local/lib/python1.5/tkinter']


Python已经开始了

…由外部纯python模块实现:)

1
2
3
4
5
6
7
8
9
from goto import goto, label
for i in range(1, 10):
    for j in range(1, 20):
        for k in range(1, 30):
            print i, j, k
            if k == 3:
                goto .end # breaking out from a deeply nested loop
label .end
print"Finished"

dict的构造函数接受关键字参数:

1
2
>>> dict(foo=1, bar=2)
{'foo': 1, 'bar': 2}


序列乘法和反射操作数

1
2
3
4
5
6
7
8
>>> 'xyz' * 3
'xyzxyzxyz'

>>> [1, 2] * 3
[1, 2, 1, 2, 1, 2]

>>> (1, 2) * 3
(1, 2, 1, 2, 1, 2)

我们用反射(交换)操作数得到相同的结果

1
2
>>> 3 * 'xyz'
'xyzxyzxyz'

工作原理如下:

1
2
>>> s = 'xyz'
>>> num = 3

要计算表达式s*num解释器,调用s.uuuuu muluuuuuuu(num)

1
2
3
4
5
>>> s * num
'xyzxyzxyz'

>>> s.__mul__(num)
'xyzxyzxyz'

要计算表达式num*s解释器,请调用num。

1
2
3
4
5
>>> num * s
'xyzxyzxyz'

>>> num.__mul__(s)
NotImplemented

如果调用返回NotImplemented,则解释程序调用如果操作数的类型不同,则返回操作s。

1
2
>>> s.__rmul__(num)
'xyzxyzxyz'

请参见http://docs.python.org/reference/datamodel.html object.rmul


Interleaving if and for in list comprehensions

1
2
>>> [(x, y) for x in range(4) if x % 2 == 1 for y in range(4)]
[(1, 0), (1, 1), (1, 2), (1, 3), (3, 0), (3, 1), (3, 2), (3, 3)]

直到我学会哈斯克尔我才意识到这一点。


模块运算符中的getter函数

模块operator中的函数attrgetter()itemgetter()可用于生成用于排序和搜索对象和字典的快速访问函数。

python库文档中的第6.7章


显然,反重力模块。XKCDα353


tuple解包:

1
2
3
4
5
6
7
>>> (a, (b, c), d) = [(1, 2), (3, 4), (5, 6)]
>>> a
(1, 2)
>>> b
3
>>> c, d
(4, (5, 6))

更模糊的是,您可以在函数参数中这样做(在python 2.x中;python 3.x将不再允许这样做):

1
2
3
4
>>> def addpoints((x1, y1), (x2, y2)):
...     return (x1+x2, y1+y2)
>>> addpoints((5, 0), (3, 5))
(8, 5)


python解释器

1
>>>

也许不鲜为人知,但肯定是我最喜欢的Python特性之一。


简单的:

1
2
3
4
5
>>> 'str' in 'string'
True
>>> 'no' in 'yes'
False
>>>

关于Python,我很喜欢它,我看到过很多不太像Python的习语:

1
2
if 'yes'.find("no") == -1:
    pass


在构建列表时引用列表理解…

您可以引用一个列表理解,因为它是由符号"[1]"构建的。例如,下面的函数唯一地表示元素列表,而不通过引用其列表理解来更改它们的顺序。

1
2
def unique(my_list):
    return [x for x in my_list if x not in locals()['_[1]']]

sort函数Python元组(即:正确使用熟悉的lexicographical Order):

1
2
3
a = [(2,"b"), (1,"a"), (2,"a"), (3,"c")]
print sorted(a)
#[(1, 'a'), (2, 'a'), (2, 'b'), (3, 'c')]

有用的,如果你想排序列表,然后后时代的人的名字。


解包语法已在最新版本中升级,如示例中所示。

1
2
3
4
5
6
7
8
9
>>> a, *b = range(5)
>>> a, b
(0, [1, 2, 3, 4])
>>> *a, b = range(5)
>>> a, b
([0, 1, 2, 3], 4)
>>> a, *b, c = range(5)
>>> a, b, c
(0, [1, 2, 3], 4)

我个人喜欢这三个不同的引语

1
2
3
4
5
str ="I'm a string 'but still I can use quotes' inside myself!"
str =""" For some messy multi line strings.
Such as
<html>
<head> ... </head>"""

也很酷:不必逃避正则表达式,使用原始字符串来避免可怕的反斜杠沙拉:

1
2
3
4
str2 = r"
"

print str2
>>


元类

当然:-)什么是Python中的元类?


发电机

我认为很多刚开始的Python开发人员都忽略了生成器,而没有真正了解它们的用途或对它们的能力有任何了解。直到我读到大卫·M·比兹利关于发电机的Pycon演示(这里有),我才意识到它们有多有用(本质上是真的)。这个演示说明了对我来说是一种全新的编程方式,我向任何不了解生成器的人推荐它。


隐式连接:

1
2
>>> print"Hello""World"
Hello World

当要使长文本适合脚本中的多行时很有用:

1
2
hello ="Greaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Hello" \
       "Word"

1
2
hello = ("Greaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Hello"
        "Word")


使用交互式shell时,"_uu"包含最后一个打印项的值:

1
2
3
4
5
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> _
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>


python中的textwrap.dedent实用程序函数可以非常方便地进行测试,即返回的多行字符串等于预期输出,而不会破坏unittests的缩进:

1
2
3
4
5
6
7
8
9
10
11
12
13
import unittest, textwrap

class XMLTests(unittest.TestCase):
    def test_returned_xml_value(self):
        returned_xml = call_to_function_that_returns_xml()
        expected_value = textwrap.dedent("""\
        <?xml version="1.0" encoding="utf-8"?>
        <root_node>
            <my_node>my_content</my_node>
        </root_node>
       """
)

        self.assertEqual(expected_value, returned_xml)


零参数和变参数lambdas

lambda函数通常用于将一个值快速转换为另一个值,但也可用于将值包装在函数中:

1
2
3
>>> f = lambda: 'foo'
>>> f()
'foo'

他们还可以接受通常的*args**kwargs语法:

1
2
3
>>> g = lambda *args, **kwargs: args[0], kwargs['thing']
>>> g(1, 2, 3, thing='stuff')
(1, 'stuff')


使用关键字参数作为赋值

有时,人们希望根据一个或多个参数构建一系列函数。但是,这很容易导致闭包引用相同的对象和值:

1
2
3
4
5
6
7
8
funcs = []
for k in range(10):
     funcs.append( lambda: k)

>>> funcs[0]()
9
>>> funcs[7]()
9

通过将lambda表达式转换为仅依赖于其参数的函数,可以避免此行为。关键字参数存储绑定到它的当前值。函数调用不必更改:

1
2
3
4
5
6
7
8
funcs = []
for k in range(10):
     funcs.append( lambda k = k: k)

>>> funcs[0]()
0
>>> funcs[7]()
7


mod与负数一起正常工作

-1%5应该是4,而不是其他语言如javascript中的-1。这使得python中的"wraporaund windows"更干净,只需执行以下操作:

1
index = (index + increment) % WINDOW_SIZE


不是很隐蔽,但函数具有以下属性:

1
2
3
4
5
6
def doNothing():
    pass

doNothing.monkeys = 4
print doNothing.monkeys
4


字典中无限递归的良好处理:

1
2
3
4
5
6
>>> a = {}
>>> b = {}
>>> a['b'] = b
>>> b['a'] = a
>>> print a
{'b': {'a': {...}}}


分配和删除切片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> a = range(10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:5] = [42]
>>> a
[42, 5, 6, 7, 8, 9]
>>> a[:1] = range(5)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> del a[::2]
>>> a
[1, 3, 5, 7, 9]
>>> a[::2] = a[::-2]
>>> a
[9, 3, 5, 7, 1]

注意:当分配给扩展片(s[start:stop:step]时,分配的iterable必须与切片具有相同的长度。


将元组传递给内置函数

许多python函数接受元组,但看起来也不是这样。例如,要测试变量是否为数字,可以执行以下操作:

1
2
if isinstance (number, float) or isinstance (number, int):  
   print"yaay"

但如果你超过我们,这看起来更干净:

1
2
if isinstance (number, (float, int)):  
   print"yaay"

三元运算符

1
2
3
4
>>> 'ham' if True else 'spam'
'ham'
>>> 'ham' if False else 'spam'
'spam'

这是添加到现有2.5,你可以使用:

1
2
3
4
>>> True and 'ham' or 'spam'
'ham'
>>> False and 'ham' or 'spam'
'spam'

然而,如果你想与我们的价值观被视为假,有一个差分:

1
2
3
4
>>> [] if True else 'spam'
[]
>>> True and [] or 'spam'
'spam'


第一类函数

这并不是一个隐藏的特性,但是函数是第一类对象的事实是非常好的。你可以像其他变量一样传递它们。

1
2
3
4
5
6
7
>>> def jim(phrase):
...   return 'Jim says,"%s".' % phrase
>>> def say_something(person, phrase):
...   print person(phrase)

>>> say_something(jim, 'hey guys')
'Jim says,"hey guys".'


用负阶跃来逆转一个不可测的

1
2
3
4
5
6
7
8
9
>>> 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]


可以说,这本身不是一个编程特性,但是非常有用,所以我还是要发布它。

1
$ python -m http.server

…接着是其他地方的$ wget http://:8000/filename

如果仍在运行旧版(2.x)的python:

1
$ python -m SimpleHTTPServer

您还可以指定一个端口,例如python -m http.server 80(这样,如果服务器端有根目录,则可以省略URL中的端口)


不是"隐藏",但非常有用,不常用

像这样快速创建字符串连接函数

1
2
3
4
5
 comma_join =",".join
 semi_join  =";".join

 print comma_join(["foo","bar","baz"])
 'foo,bar,baz

能够创建比引号更优雅的字符串列表,逗号混乱。

1
l = ["item1","item2","item3"]

被替换

1
l ="item1 item2 item3".split()


从python 3.1(2.7)字典和集合理解得到支持:

1
2
{ a:a for a in range(10) }
{ a for a in range(10) }


对迭代器的多个引用

可以使用列表乘法创建对同一迭代器的多个引用:

1
2
3
4
5
6
7
8
>>> i = (1,2,3,4,5,6,7,8,9,10) # or any iterable object
>>> iterators = [iter(i)] * 2
>>> iterators[0].next()
1
>>> iterators[1].next()
2
>>> iterators[0].next()
3

这可用于将ITerable分组为块,例如,在本例中,来自itertools文档

1
2
3
4
def grouper(n, iterable, fillvalue=None):
   "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

python可以理解任何一种Unicode数字,而不仅仅是ASCII数字:

1
2
3
4
5
6
7
8
9
>>> s = u'10585'
>>> s
u'\uff11\uff10\uff15\uff18\uff15'
>>> print s
10585
>>> int(s)
10585
>>> float(s)
10585.0


操作系统模块

您可以直接操作模块缓存,使模块可用或不可用,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> import sys
>>> import ham
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
ImportError: No module named ham

# Make the 'ham' module available -- as a non-module object even!
>>> sys.modules['ham'] = 'ham, eggs, saussages and spam.'
>>> import ham
>>> ham
'ham, eggs, saussages and spam.'

# Now remove it again.
>>> sys.modules['ham'] = None
>>> import ham
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
ImportError: No module named ham

这甚至适用于可用的模块,在某种程度上也适用于已导入的模块:

1
2
3
4
5
6
7
8
9
10
>>> import os
# Stop future imports of 'os'.
>>> sys.modules['os'] = None
>>> import os
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
ImportError: No module named os
# Our old imported module is still available.
>>> os
<module 'os' from '/usr/lib/python2.5/os.pyc'>

如最后一行所示,更改sys.modules只会影响未来的import语句,而不是过去的语句,因此,如果要影响其他模块,在给它们机会尝试导入模块之前进行这些更改是很重要的,因此通常在导入模块之前。Nonesys.modules中的一个特殊值,用于负缓存(表示第一次找不到模块,因此没有必要再查找)。任何其他值都将是import操作的结果,即使它不是模块对象。您可以使用它将模块替换为行为完全符合您需要的对象。从sys.modules中删除条目完全会导致下一个import对模块进行正常搜索,即使它以前已经导入过。


迭代工具

这个模块经常被忽视。下面的示例使用itertools.chain()。要展平列表:

1
2
3
4
>>> from itertools import *
>>> l = [[1, 2], [3, 4]]
>>> list(chain(*l))
[1, 2, 3, 4]

更多应用程序请参见http://docs.python.org/library/itertools.html食谱。


__slots__是一种保存内存的好方法,但是很难对对象的值进行听写。想象一下以下对象:

1
2
class Point(object):
    __slots__ = ('x', 'y')

现在这个对象显然有两个属性。现在,我们可以创建它的一个实例,并以这种方式构建它的dict:

1
2
3
4
5
>>> p = Point()
>>> p.x = 3
>>> p.y = 5
>>> dict((k, getattr(p, k)) for k in p.__slots__)
{'y': 5, 'x': 3}

但是,如果点是子类的,并且添加了新的槽,这将不起作用。然而,python自动实现__reduce_ex__以帮助copy模块。这可以被滥用以获得价值观:

1
2
>>> p.__reduce_ex__(2)[2][1]
{'y': 5, 'x': 3}


您可以通过查看它的模块属性来询问任何对象它来自哪个模块。例如,如果您正在命令行中进行试验,并且导入了很多东西,那么这很有用。

同样,您可以通过查看模块的"文件"属性来询问模块的来源。这在调试路径问题时很有用。


猜测整数基数

1
2
3
4
5
6
7
8
9
10
>>> int('10', 0)
10
>>> int('0x10', 0)
16
>>> int('010', 0)  # does not work on Python 3.x
8
>>> int('0o10', 0)  # Python >=2.6 and Python 3.x
8
>>> int('0b10', 0)  # Python >=2.6 and Python 3.x
2

一些内置的收藏夹map()、reduce()和filter()。一切都非常迅速和强大。


一言以蔽之:伊普生

制表符内省、精美打印、%debug、历史管理、pylab……值得花时间好好学习。


在子类中扩展属性(定义为描述符)

有时它对于扩展(修改)子类中描述符"返回"的值很有用。使用super()可以很容易地完成:

1
2
3
4
5
6
7
8
9
class A(object):
    @property
    def prop(self):
        return {'a': 1}

class B(A):
    @property
    def prop(self):
        return dict(super(B, self).prop, b=2)

将其存储在test.py中并运行python -i test.py(另一个隐藏功能:-i选项执行脚本并允许您继续交互模式):

1
2
>>> B().prop
{'a': 1, 'b': 2}

你可以建立一套词典从A - 2序列的长度。当你的手机有一个列表和列表中的值的数组。

1
2
3
4
5
6
7
>>> dict([ ('foo','bar'),('a',1),('b',2) ])
{'a': 1, 'b': 2, 'foo': 'bar'}

>>> names = ['Bob', 'Marie', 'Alice']
>>> ages = [23, 27, 36]
>>> dict(zip(names, ages))
{'Alice': 36, 'Bob': 23, 'Marie': 27}

Python的一种轻微的畸形。将字符串列表连接在一起的正常快速方法是,

1
''.join(list_of_strings)


创建枚举

在python中,可以这样做以快速创建枚举:

1
2
3
>>> FOO, BAR, BAZ = range(3)
>>> FOO
0

但"枚举"不必具有整数值。你甚至可以这样做:

1
2
3
4
5
class Colors(object):
    RED, GREEN, BLUE, YELLOW = (255,0,0), (0,255,0), (0,0,255), (0,255,255)

#now Colors.RED is a 3-tuple that returns the 24-bit 8bpp RGB
#value for saturated red


re.Scanner类。http://code.activestate.com/recipes/457664-hidden-scanner-functionality-in-re-module/


对象数据模型

您可以为自己的类重写语言中的任何运算符。有关完整列表,请参阅此页。一些例子:

  • 您可以覆盖任何操作符(* + - / // % ^ == < > <= >= .等)。所有这些都是通过覆盖对象中的__mul____add__等来完成的。你甚至可以覆盖像__rmul__这样的东西来分别处理your_object*something_elsesomething_else*your_object.是属性访问(a.b),可以通过使用__getattr__覆盖来处理任意b。这里还包括使用__call__a(…)

  • 您可以创建自己的切片语法(a[stuff]),它非常复杂,并且与列表中使用的标准语法(numpy在其数组中有一个很好的例子说明了这一点)有很大的不同,可以使用您喜欢的任何组合,:,使用切片对象。

  • 特别处理语言中的许多关键字所发生的事情。包括:delinimportnot

  • 处理用对象调用许多内置函数时发生的情况。标准的__int____str__等都在这里,但是__len____reversed____abs__和三个参数__pow__也在这里。


在运行时更改函数标签:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> class foo:
...   def normal_call(self): print"normal_call"
...   def call(self):
...     print"first_call"
...     self.call = self.normal_call

>>> y = foo()
>>> y.call()
first_call
>>> y.call()
normal_call
>>> y.call()
normal_call
...


string-escapeunicode-escape编码

假设您有一个来自外部源的字符串,它包含
\t等。如何将它们转换为新行或制表符?只需使用string-escape编码解码字符串!

1
2
3
4
5
6
>>> print s
Hello
Stack\toverflow
>>> print s.decode('string-escape')
Hello
Stack   overflow

另一个问题。您有一个普通的字符串,其中包含像\u01245这样的Unicode文本。如何使其工作?只需使用unicode-escape编码解码字符串!

1
2
3
4
5
6
7
>>> s = '\u041f\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442!'
>>> print s
\u041f\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442!
>>> print unicode(s)
\u041f\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442!
>>> print unicode(s, 'unicode-escape')
Прив?т, св?т!


"解包"的功能参数。

1
2
3
4
5
def foo(a, b, c):
        print a, b, c

bar = (3, 14, 15)
foo(*bar)

当执行打印。

1
3 14 15


reversed()内置。在许多情况下,它使迭代更加清晰。

快速实例:

1
2
for i in reversed([1, 2, 3]):
    print(i)

生产:

1
2
3
3
2
1

但是,reversed()也适用于任意迭代器,例如文件中的行或生成器表达式。


Python禅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you'
re Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let'
s do more of those!


动态添加的属性

如果您只想通过调用类向类中添加一些属性,那么这可能很有用。这可以通过重写在使用点操作数时调用的__getattribute__成员函数来实现。因此,我们来看一个虚拟类,例如:

1
2
3
4
class Dummy(object):
    def __getattribute__(self, name):
        f = lambda: 'Hello with %s'%name
        return f

当您实例化一个虚拟对象并执行一个方法调用时,您将得到以下内容:

1
2
3
>>> d = Dummy()
>>> d.b()
'Hello with b'

最后,您甚至可以将属性设置为类,以便对其进行动态定义。如果您使用python web框架并希望通过解析属性的名称来进行查询,那么这将非常有用。

我在Github有一个要点,这里有一个简单的代码,它相当于一个朋友在Ruby上编写的代码。

当心!


绝密属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> class A(object): pass
>>> a = A()
>>> setattr(a,"can't touch this", 123)
>>> dir(a)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',"can't touch this"]
>>> a.can't touch this # duh
  File"<stdin>", line 1
    a.can'
t touch this
                     ^
SyntaxError: EOL while scanning string literal
>>> getattr(a,"can't touch this")
123
>>> setattr(a,"__class__.__name__",":O")
>>> a.__class__.__name__
'A'
>>> getattr(a,"__class__.__name__")
':O'

sum()压平list

sum()内置功能可用于__add__list的组合,为listlist的展平提供了一种简便的方法:

1
2
3
4
5
6
Python 2.7.1 (r271:86832, May 27 2011, 21:41:45)
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type"help","copyright","credits" or"license" for more information.
>>> l = [[1, 2, 3], [4, 5], [6], [7, 8, 9]]
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]


namedTuple是一个元组

1
2
3
4
5
6
>>> node = namedtuple('node',"a b")
>>> node(1,2) + node(5,6)
(1, 2, 5, 6)
>>> (node(1,2), node(5,6))
(node(a=1, b=2), node(a=5, b=6))
>>>

更多的实验来回应评论:

1
2
3
4
5
6
7
8
9
10
11
>>> from collections import namedtuple
>>> from operator import *
>>> mytuple = namedtuple('A',"a b")
>>> yourtuple = namedtuple('Z',"x y")
>>> mytuple(1,2) + yourtuple(5,6)
(1, 2, 5, 6)
>>> q = [mytuple(1,2), yourtuple(5,6)]
>>> q
[A(a=1, b=2), Z(x=5, y=6)]
>>> reduce(operator.__add__, q)
(1, 2, 5, 6)

因此,namedtupletuple的一个有趣的亚型。


博格模式

这是亚历克斯·马泰利的杀手。Borg共享状态的所有实例。这消除了使用单例模式的需要(实例在状态共享时并不重要),并且相当优雅(但在新类中更复杂)。

EDOCX1[22]的值可以在任何情况下重新分配,并且所有值都将更新,您甚至可以重新分配整个dict。borg是完美的名称,请在此处阅读更多信息。

1
2
3
4
5
class Borg:
    __shared_state = {'foo': 'bar'}
    def __init__(self):
        self.__dict__ = self.__shared_state
    # rest of your class here

这非常适合共享eventlet.greenpool来控制并发性。


在python中需要解压

有人在博客中提到python没有unzip函数可用于zip()。解压是直接计算的,因为:

1
2
3
4
>>> t1 = (0,1,2,3)
>>> t2 = (7,6,5,4)
>>> [t1,t2] == zip(*zip(t1,t2))
True

不过,经过深思熟虑,我还是希望有一个显式的unzip()。


创建包含相关数据的两个序列的字典

1
2
3
4
5
6
In [15]: t1 = (1, 2, 3)

In [16]: t2 = (4, 5, 6)

In [17]: dict (zip(t1,t2))
Out[17]: {1: 4, 2: 5, 3: 6}


pdb-python调试器

作为一个程序员,真正的程序开发首先需要的是一个调试器。python有一个内置的模块,称为pdb(对于"python debugger",当然是!).

http://docs.python.org/library/pdb.html网站


线程。枚举()提供对系统中所有线程对象的访问,并且sys .x CurrutyFraseMe()返回系统中所有线程的当前堆栈帧,因此将两者结合起来,得到Java样式堆栈转储:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def dumpstacks(signal, frame):
    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("
# Thread: %s(%d)"
% (id2name[threadId], threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File:"%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    print"
"
.join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)

在多线程python程序开始时执行此操作,您可以通过发送sigquit随时访问线程的当前状态。您也可以选择signal.sigusr1或signal.sigusr2。


原始字符串中的反斜杠仍然可以转义引号。看到这个:

1
2
>>> print repr(r"aaa"bbb")
'aaa\"bbb'

请注意,反斜杠和双引号都出现在最后一个字符串中。

因此,不能以反斜杠结束原始字符串:

1
2
3
4
>>> print repr(r"C:")
SyntaxError: EOL while scanning string literal
>>> print repr(r"C:"")
'C:\"'

这是因为实现原始字符串是为了帮助编写正则表达式,而不是为了编写Windows路径。在gotcha-backslashes的windows文件名中阅读关于这个的长讨论。


运算符可以作为函数调用:

1
2
from operator import add
print reduce(add, [1,2,3,4,5,6])


dict.get()的默认值为无,从而避免了键错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
In [1]: test = { 1 : 'a' }

In [2]: test[2]
---------------------------------------------------------------------------
<type 'exceptions.KeyError'>              Traceback (most recent call last)

&lt;ipython console&gt; in <module>()

<type 'exceptions.KeyError'>: 2

In [3]: test.get( 2 )

In [4]: test.get( 1 )
Out[4]: 'a'

In [5]: test.get( 2 ) == None
Out[5]: True

甚至在"场景"中指定:

1
2
In [6]: test.get( 2, 'Some' ) == 'Some'
Out[6]: True

您可以使用setdefault(设置一个值,如果该值不存在,则返回该值:

1
2
3
4
5
6
>>> a = {}
>>> b = a.setdefault('foo', 'bar')
>>> a
{'foo': 'bar'}
>>> b
'bar

重新加载模块启用"实时编码"样式。但是类实例不会更新。这就是为什么,以及如何绕过它。记住,一切,是的,一切都是一个物体。

1
2
3
4
5
>>> from a_package import a_module
>>> cls = a_module.SomeClass
>>> obj = cls()
>>> obj.method()
(old method output)

现在,您在一个_module.py中更改方法,并希望更新您的对象。

1
2
3
4
5
>>> reload(a_module)
>>> a_module.SomeClass is cls
False # Because it just got freshly created by reload.
>>> obj.method()
(old method output)

有一种方法可以更新它(但考虑使用剪刀运行它):

1
2
3
4
5
>>> obj.__class__ is cls
True # it's the old class object
>>> obj.__class__ = a_module.SomeClass # pick up the new class
>>> obj.method()
(new method output)

这是"用剪刀运行",因为对象的内部状态可能与新类期望的不同。这适用于非常简单的情况,但除此之外,pickle是您的朋友。不过,了解这一点还是很有帮助的。


列表中的无限递归

1
2
3
4
5
6
7
8
>>> a = [1,2]
>>> a.append(a)
>>> a
[1, 2, [...]]
>>> a[2]
[1, 2, [...]]
>>> a[2][2][2][2][2][2][2][2][2] == a
True


检查模块也是一个很酷的功能。


舍入整数:python有round函数,它返回double类型的数字:

1
2
3
4
5
6
 >>> print round(1123.456789, 4)
1123.4568
 >>> print round(1123.456789, 2)
1123.46
 >>> print round(1123.456789, 0)
1123.0

这个函数有一个奇妙的魔力:

1
2
3
4
 >>> print round(1123.456789, -1)
1120.0
 >>> print round(1123.456789, -2)
1100.0

如果结果需要整数,请使用int转换类型:

1
2
3
4
 >>> print int(round(1123.456789, -2))
1100
 >>> print int(round(8359980, -2))
8360000

谢谢你,格雷戈。


操作递归限制

获取或设置sys.getRecursionLimit()和sys.setRecursionLimit()的最大递归深度。

我们可以限制它以防止由无限递归引起的堆栈溢出。


能够替换文件删除、文件打开等内容——直接操作语言库。这在测试时是一个巨大的优势。你不必把所有东西都包装在复杂的容器里。只需替换一个函数/方法就可以了。这也被称为猴子修补。


您可以用类来修饰函数-用类实例替换函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class countCalls(object):
   """ decorator replaces a function with a"countCalls" instance
    which behaves like the original function, but keeps track of calls

    >>> @countCalls
    ... def doNothing():
    ...     pass
    >>> doNothing()
    >>> doNothing()
    >>> print doNothing.timesCalled
    2
   """

    def __init__ (self, functionToTrack):
        self.functionToTrack = functionToTrack
        self.timesCalled = 0
    def __call__ (self, *args, **kwargs):
        self.timesCalled += 1
        return self.functionToTrack(*args, **kwargs)

如果在序列的最后一个元素之后找到,python 2.x将忽略逗号:

1
2
3
4
>>> a_tuple_for_instance = (0,1,2,3,)
>>> another_tuple = (0,1,2,3)
>>> a_tuple_for_instance == another_tuple
True

尾随逗号导致单个带圆括号元素被视为序列:

1
>>> a_tuple_with_one_element = (8,)


切片和易变性

复制列表

1
2
3
4
5
6
7
8
>>> x = [1,2,3]
>>> y = x[:]
>>> y.pop()
3
>>> y
[1, 2]
>>> x
[1, 2, 3]

替换列表

1
2
3
4
5
>>> x = [1,2,3]
>>> y = x
>>> y[:] = [4,5,6]
>>> x
[4, 5, 6]


嵌套函数参数重新绑定

1
2
3
4
5
def create_printers(n):
    for i in xrange(n):
        def printer(i=i): # Doesn't work without the i=i
            print i
        yield printer


切成薄片。这个筛子的埃拉托斯滕斯产生一个列表,要么有素数或0。元素在循环中的切片分配为0'd。

1
2
3
4
5
6
7
8
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)

要工作,必须在左侧的切片的右侧指定一个长度相同的列表。


内置方法或函数不实现描述符协议,这使得不可能执行如下操作:

1
2
3
4
5
6
7
>>> class C(object):
...  id = id
...
>>> C().id()
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
TypeError: id() takes exactly one argument (0 given)

但是,您可以创建一个小的绑定描述符,使这成为可能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> from types import MethodType
>>> class bind(object):
...  def __init__(self, callable):
...   self.callable = callable
...  def __get__(self, obj, type=None):
...   if obj is None:
...    return self
...   return MethodType(self.callable, obj, type)
...
>>> class C(object):
...  id = bind(id)
...
>>> C().id()
7414064


可以用元类重写类的MRO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
>>> class A(object):
...     def a_method(self):
...         print("A")
...
>>> class B(object):
...     def b_method(self):
...         print("B")
...
>>> class MROMagicMeta(type):
...     def mro(cls):
...         return (cls, B, object)
...
>>> class C(A, metaclass=MROMagicMeta):
...     def c_method(self):
...         print("C")
...
>>> cls = C()
>>> cls.c_method()
C
>>> cls.a_method()
Traceback (most recent call last):
 File"<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'a_method'
>>> cls.b_method()
B
>>> type(cls).__bases__
(<class '__main__.A'>,)
>>> type(cls).__mro__
(<class '__main__.C'>, <class '__main__.B'>, <class 'object'>)

它可能是出于一个很好的原因而隐藏起来的。:)


除HaridsV之前提到的内容外:

1
2
3
>>> foo = bar = baz = 1
>>> foo, bar, baz
(1, 1, 1)

也可以这样做:

1
2
3
>>> foo, bar, baz = 1, 2, 3
>>> foo, bar, baz
(1, 2, 3)


暴露可变缓冲区

使用python buffer协议在python(2.5/2.6)中公开可变的面向字节的缓冲区。

(对不起,这里没有密码。需要使用低级C API或现有适配器模块)。


_ _ getattr _ _()

getattr是一个通用类是很好的方式做,这是特别有用的,如果你写的API。例如,在fogbugz Python API,getattr通法是用来调用Web服务seamlessly on to the:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class FogBugz:
    ...

    def __getattr__(self, name):
        # Let's leave the private stuff to Python
        if name.startswith("__"):
            raise AttributeError("No such attribute '%s'" % name)

        if not self.__handlerCache.has_key(name):
            def handler(**kwargs):
                return self.__makerequest(name, **kwargs)
            self.__handlerCache[name] = handler
        return self.__handlerCache[name]
    ...

当有人呼叫FogBugz.search(q='bug'),他们don’t get a search实际调用的方法。相反,在getattr句柄调用函数创建一个新的makerequest工艺品包装方法是适当的HTTP请求到Web API。的任何错误将被传递到Web服务和用户的反馈。


集合理解

1
2
>>> {i**2 for i in range(5)}                                                      
set([0, 1, 4, 16, 9])

python文档

维基百科条目


听写理解

1
2
>>> {i: i**2 for i in range(5)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

python文档

维基百科条目


列表解析

列表推导式

比较更传统的(没有列表理解):

1
2
3
4
foo = []
for x in xrange(10):
  if x % 2 == 0:
     foo.append(x)

到:

1
foo = [x for x in xrange(10) if x % 2 == 0]


Python习语x = ... if ... else ...远优于x = ... and ... or ...,原因如下:

尽管声明

1
x = 3 if (y == 1) else 2

等于

1
x = y == 1 and 3 or 2

如果你使用x = ... and ... or ...习惯用法,总有一天你可能会被这种棘手的情况咬到:

1
x = 0 if True else 1    # sets x equal to 0

因此不等于

1
x = True and 0 or 1   # sets x equal to 1

更多关于正确方法的信息,请参见python的隐藏特性。


我不确定这在python文档中的位置(或者是否在其中),但是对于python 2.x(至少2.5和2.6,我刚刚尝试过),可以用parenthenses调用print语句。如果您希望能够轻松地将一些python 2.x代码移植到python 3.x,这将非常有用。

例子:print('We want Moshiach Now')应该用python 2.5、2.6和3.x打印We want Moshiach Now工作。

另外,可以在python 2和3中使用parenthenses调用not操作符:not Falsenot(False)如果两者都返回True

parenthense也可以与其他语句和运算符一起使用。

编辑:把parenthenses放在not操作符(可能还有任何其他操作符)周围不是一个好主意,因为它可以产生令人惊讶的情况,就像这样(发生这种情况是因为parenthenses实际上是围绕1):

1
2
3
4
5
>>> (not 1) == 9
False

>>> not(1) == 9
True

对于某些值(我认为它不是有效的标识符名称),这也可以工作,如下所示:not'val'返回Falseprint'We want Moshiach Now'返回We want Moshiach Now。(但not552会引发一个名称错误,因为它是一个有效的标识符名称)。


简单的内置基准测试工具

python标准库提供了一个非常易于使用的基准模块,叫做"timeit"。您甚至可以从命令行使用它来查看哪种语言构造最快。

例如。,

1
2
3
4
5
% python -m timeit 'r = range(0, 1000)' 'for i in r: pass'
10000 loops, best of 3: 48.4 usec per loop

% python -m timeit 'r = xrange(0, 1000)' 'for i in r: pass'
10000 loops, best of 3: 37.4 usec per loop


如果在类上使用描述符,python将完全绕过该键的__dict__,这使它成为存储此类值的好地方:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> class User(object):
...  def _get_username(self):
...   return self.__dict__['username']
...  def _set_username(self, value):
...   print 'username set'
...   self.__dict__['username'] = value
...  username = property(_get_username, _set_username)
...  del _get_username, _set_username
...
>>> u = User()
>>> u.username ="foo"
username set
>>> u.__dict__
{'username': 'foo'}

这有助于保持dir()的清洁。


这里有两个复活节彩蛋:

一个在python本身:

1
2
>>> import __hello__
Hello world...

Werkzeug模块中的另一个模块,它的显示有点复杂,这里是:

通过查看Werkzeug的源代码,在werkzeug/__init__.py中有一行应该引起您的注意:

1
'werkzeug._internal':   ['_easteregg']

如果你有点好奇,这会让你看看werkzeug/_internal.py,在那里,你会发现一个_easteregg()函数,它接受一个wsgi应用程序作为参数,它还包含一些base64编码的数据和2个嵌套的函数,如果在查询字符串中找到一个名为macgybarchakku的参数,它似乎会做一些特别的事情。

因此,要显示这个复活节彩蛋,您似乎需要在_easteregg()函数中包装一个应用程序,让我们开始:

1
2
3
4
5
6
7
8
from werkzeug import Request, Response, run_simple
from werkzeug import _easteregg

@Request.application
def application(request):
    return Response('Hello World!')

run_simple('localhost', 8080, _easteregg(application))

现在,如果您运行应用程序并访问http://localhost:8080/?麦加巴查库,你应该看看复活节彩蛋。


MonkeyPatching对象

python中的每个对象都有一个__dict__成员,它存储对象的属性。所以,你可以这样做:

1
2
3
4
5
6
7
class Foo(object):
    def __init__(self, arg1, arg2, **kwargs):
        #do stuff with arg1 and arg2
        self.__dict__.update(kwargs)

f = Foo('arg1', 'arg2', bar=20, baz=10)
#now f is a Foo object with two extra attributes

这可以用来任意地向对象添加属性和函数。这也可以用来创建一个快速和肮脏的struct类型。

1
2
3
4
5
class struct(object):
    def __init__(**kwargs):
       self.__dict__.update(kwargs)

s = struct(foo=10, bar=11, baz="i'm a string!')

getattr采用第三个参数

getattr(obj, attribute_name, default)类似于:

1
2
3
4
try:
    return obj.attribute
except AttributeError:
    return default

attribute_name可以是任何字符串。

这对鸭子打字很有用。也许你有这样的东西:

1
2
3
4
5
6
class MyThing:
    pass
class MyOtherThing:
    pass
if isinstance(obj, (MyThing, MyOtherThing)):
    process(obj)

(btw,isinstance(obj, (a,b))表示isinstance(obj, a) or isinstance(obj, b))

当你做一种新的东西时,你需要在它出现的任何地方把它添加到这个元组中。(这种构造在重新加载模块或以两个名称导入同一文件时也会导致问题。这种情况发生的次数比人们愿意承认的要多。)但相反,你可以说:

1
2
3
4
5
6
class MyThing:
    processable = True
class MyOtherThing:
    processable = True
if getattr(obj, 'processable', False):
    process(obj)

添加继承,它会变得更好:所有可处理对象的示例都可以继承自

1
2
class Processable:
    processable = True

但您不必说服所有人继承您的基类,只需设置一个属性。


太懒了,无法初始化字典中的每个字段?没问题:

在python>2.3中:

1
from collections import defaultdict

在python中<=2.3:

1
2
3
4
5
def defaultdict(type_):
    class Dict(dict):
        def __getitem__(self, key):
            return self.setdefault(key, type_())
    return Dict()

在任何版本中:

1
2
3
d = defaultdict(list)
for stuff in lots_of_stuff:
     d[stuff.name].append(stuff)

更新:

谢谢肯·阿诺德。我重新实现了更复杂的defaultdict版本。它的行为应该与标准库中的行为完全相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def defaultdict(default_factory, *args, **kw):                              

    class defaultdict(dict):

        def __missing__(self, key):
            if default_factory is None:
                raise KeyError(key)
            return self.setdefault(key, default_factory())

        def __getitem__(self, key):
            try:
                return dict.__getitem__(self, key)
            except KeyError:
                return self.__missing__(key)

    return defaultdict(*args, **kw)

进口反重力


特殊方法

绝对的力量!


python对于非常意外的事情有例外:

进口

这样可以在缺少lib时导入替代项

1
2
3
4
try:
    import json
except ImportError:
    import simplejson as json

迭代

对于循环,在内部执行此操作,并捕获StopIteration:

1
2
3
4
5
iter([]).next()
Traceback (most recent call last):
  File"<pyshell#4>", line 1, in <module>
    iter(a).next()
StopIteration

断言

1
2
3
4
5
>>> try:
...     assert []
... except AssertionError:
...     print"This list should not be empty"
This list should not be empty

虽然这对于一个检查来说更为冗长,但是可以通过这种方式缩短将异常和具有相同错误消息的布尔运算符混合在一起的多个检查。


python3中的Unicode标识符:

1
2
3
4
5
>>> 'Unicode字符_?????_Variable'.isidentifier()
True
>>> Unicode字符_?????_Variable='Python3 rules!'
>>> Unicode字符_?????_Variable
'Python3 rules!'


Access Dictionary elements as
attributes (properties). so if an
a1=AttrDict() has key 'name' ->
instead of a1['name'] we can easily
access name attribute of a1 using ->
a1.name

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class AttrDict(dict):

    def __getattr__(self, name):
        if name in self:
            return self[name]
        raise AttributeError('%s not found' % name)

    def __setattr__(self, name, value):
        self[name] = value

    def __delattr__(self, name):
        del self[name]

person = AttrDict({'name': 'John Doe', 'age': 66})
print person['name']
print person.name

person.name = 'Frodo G'
print person.name

del person.age

print person

通过一分钟的工作量,线程模块变得非常容易使用。这个修饰器更改一个函数,使它在自己的线程中运行,返回一个占位符类实例,而不是它的常规结果。您可以通过检查placeolder.result来探测答案,或者通过调用placeholder.wait result()来等待答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def threadify(function):
   """
    exceptionally simple threading decorator. Just:
    >>> @threadify
    ... def longOperation(result):
    ...     time.sleep(3)
    ...     return result
    >>> A= longOperation("A has finished")
    >>> B= longOperation("B has finished")

    A doesn't have a result yet:
    >>> print A.result
    None

    until we wait for it:
    >>> print A.awaitResult()
    A has finished

    we could also wait manually - half a second more should be enough for B:
    >>> time.sleep(0.5); print B.result
    B has finished
   """

    class thr (threading.Thread,object):
        def __init__(self, *args, **kwargs):
            threading.Thread.__init__ ( self )  
            self.args, self.kwargs = args, kwargs
            self.result = None
            self.start()
        def awaitResult(self):
            self.join()
            return self.result        
        def run(self):
            self.result=function(*self.args, **self.kwargs)
    return thr

将解包与打印功能结合使用:

1
2
3
4
5
# in 2.6 <= python < 3.0, 3.0 + the print function is native
from __future__ import print_function

mylist = ['foo', 'bar', 'some other value', 1,2,3,4]  
print(*mylist)


利用python的动态特性创建应用程序用python语法配置文件。例如,如果您有以下内容在配置文件中:

1
2
3
4
{
 "name1":"value1",
 "name2":"value2"
}

然后你可以把它读成:

1
config = eval(open("filename").read())


插入vs追加

不是功能,但可能很有趣

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

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

然后你会想:那从一开始就插入数字呢?所以:

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

但速度慢了100倍!如果我们将count设置为10**6,它将慢1000倍;这是因为insert是o(n^2),而append是o(n)。

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


对象实例的方法替换

可以替换已创建对象实例的方法。它允许您创建具有不同(特殊)功能的对象实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> class C(object):
...     def fun(self):
...         print"C.a", self
...
>>> inst = C()
>>> inst.fun()  # C.a method is executed
C.a <__main__.C object at 0x00AE74D0>
>>> instancemethod = type(C.fun)
>>>
>>> def fun2(self):
...     print"fun2", self
...
>>> inst.fun = instancemethod(fun2, inst, C)  # Now we are replace C.a by fun2
>>> inst.fun()  # ... and fun2 is executed
fun2 <__main__.C object at 0x00AE74D0>

如我们所知,在inst实例中,C.afun2()所取代(self没有改变)。

或者,我们可以使用new模块,但它自python 2.6以来已贬值:

1
2
3
4
5
6
7
>>> def fun3(self):
...     print"fun3", self
...
>>> import new
>>> inst.fun = new.instancemethod(fun3, inst, C)
>>> inst.fun()
fun3 <__main__.C object at 0x00AE74D0>

节点:此解决方案不应用作继承机制的一般替换!但在某些特定情况下(调试、模拟),它可能非常方便。

警告:此解决方案不适用于内置类型和使用槽的新样式类。


模块导出其命名空间中的所有内容

包括从其他模块导入的名称!

1
2
3
# this is"answer42.py"
from operator import *
from inspect  import *

现在测试模块中可导入的内容。

1
2
3
4
5
6
7
>>> import answer42
>>> answer42.__dict__.keys()
['gt', 'imul', 'ge', 'setslice', 'ArgInfo', 'getfile', 'isCallable', 'getsourcelines', 'CO_OPTIMIZED', 'le', 're', 'isgenerator', 'ArgSpec', 'imp', 'lt', 'delslice', 'BlockFinder', 'getargspec', 'currentframe', 'CO_NOFREE', 'namedtuple', 'rshift', 'string', 'getframeinfo', '__file__', 'strseq', 'iconcat', 'getmro', 'mod', 'getcallargs', 'isub', 'getouterframes', 'isdatadescriptor', 'modulesbyfile', 'setitem', 'truth', 'Attribute', 'div', 'CO_NESTED', 'ixor', 'getargvalues', 'ismemberdescriptor', 'getsource', 'isMappingType', 'eq', 'index', 'xor', 'sub', 'getcomments', 'neg', 'getslice', 'isframe', '__builtins__', 'abs', 'getmembers', 'mul', 'getclasstree', 'irepeat', 'is_', 'getitem', 'indexOf', 'Traceback', 'findsource', 'ModuleInfo', 'ipow', 'TPFLAGS_IS_ABSTRACT', 'or_', 'joinseq', 'is_not', 'itruediv', 'getsourcefile', 'dis', 'os', 'iand', 'countOf', 'getinnerframes', 'pow', 'pos', 'and_', 'lshift', '__name__', 'sequenceIncludes', 'isabstract', 'isbuiltin', 'invert', 'contains', 'add', 'isSequenceType', 'irshift', 'types', 'tokenize', 'isfunction', 'not_', 'istraceback', 'getmoduleinfo', 'isgeneratorfunction', 'getargs', 'CO_GENERATOR', 'cleandoc', 'classify_class_attrs', 'EndOfBlock', 'walktree', '__doc__', 'getmodule', 'isNumberType', 'ilshift', 'ismethod', 'ifloordiv', 'formatargvalues', 'indentsize', 'getmodulename', 'inv', 'Arguments', 'iscode', 'CO_NEWLOCALS', 'formatargspec', 'iadd', 'getlineno', 'imod', 'CO_VARKEYWORDS', 'ne', 'idiv', '__package__', 'CO_VARARGS', 'attrgetter', 'methodcaller', 'truediv', 'repeat', 'trace', 'isclass', 'ior', 'ismethoddescriptor', 'sys', 'isroutine', 'delitem', 'stack', 'concat', 'getdoc', 'getabsfile', 'ismodule', 'linecache', 'floordiv', 'isgetsetdescriptor', 'itemgetter', 'getblock']
>>> from answer42 import getmembers
>>> getmembers
<function getmembers at 0xb74b2924>
>>>

这是不使用from x import *和定义__all__ =的一个很好的理由。


在python中没有秘密;)


一切事物的第一类("一切都是一个物体"),以及由此造成的混乱。

1
2
3
4
5
6
7
8
9
10
11
>>> 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):

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

这展示了python的两个方面——"一切都是一个对象"的哲学走到了极端,以及使用不当或构思不当的语言语法可能导致完全不可读、不可维护的意面代码,适合于一个表达式的方法。


解包的元组中的理解和表达的循环列表发电机:

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

本研究使用的密钥,迭代过成语词典:对数据)

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

照片:

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


可以将多个变量赋给同一个值

1
2
3
>>> foo = bar = baz = 1
>>> foo, bar, baz
(1, 1, 1)

有助于以紧凑的方式将多个变量初始化为无。


一切都是动态的

"没有编译时间"。python中的一切都是运行时。模块是通过自上而下执行模块的源代码来"定义"的,就像脚本一样,得到的名称空间是模块的属性空间。同样,通过从上到下执行类主体来"定义"类,并且生成的命名空间是类的属性空间。类主体可以包含完全任意的代码——包括导入语句、循环和其他类语句。创建一个类、函数甚至模块"动态的",正如有时所要求的那样,并不难;事实上,这是不可能避免的,因为一切都是"动态的"。


如果您在应用程序中重命名了一个类,通过pickle加载用户保存的文件,并且其中一个重命名的类存储在用户的旧保存中,则无法加载到该pickle文件中。

但是,只需添加对类定义的引用,一切都很好:

例如,以前:

1
2
class Bleh:
    pass

现在,

1
2
class Blah:
    pass

因此,用户保存的pickled文件包含对bleh的引用,因为重命名而不存在bleh。修复?

1
Bleh = Blah

简单!


python有"private"变量

以双下划线开始但不是结束的变量变为私有变量,而不仅仅是通过约定。实际上,uuvar变成了classname_uvar,其中classname是创建变量的类。它们不是继承的,不能被重写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> class A:
...     def __init__(self):
...             self.__var = 5
...     def getvar(self):
...             return self.__var
...
>>> a = A()
>>> a.__var
Traceback (most recent call last):
  File"", line 1, in
AttributeError: A instance has no attribute '__var'
>>> a.getvar()
5
>>> dir(a)
['_A__var', '__doc__', '__init__', '__module__', 'getvar']
>>>


使用和或模拟第三运算符。

python中的和或运算符返回对象本身,而不是布尔值。因此:

1
2
3
4
5
6
7
8
9
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

然而,Py2.5似乎添加了一个显式的三级运算符。

1
2
3
4
    In [22]: a = 5 if True else '6'

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

好吧,如果你确定你的真子句不会被评估为假的话,这个方法是有效的。例子:

1
2
3
4
5
6
7
8
9
10
11
12
>>> def foo():
...     print"foo"
...     return 0
...
>>> def bar():
...     print"bar"
...     return 1
...
>>> 1 and foo() or bar()
foo
bar
1

要想把它弄好,你必须再多做一点:

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

不过,这并不是很漂亮。如果您的Python版本支持它,请使用条件运算符。

1
2
3
>>> foo() if True or bar()
foo
0


虽然不是很Python,但你可以使用print写入文件。

print>>outFile, 'I am Being Written'

说明:

This form is sometimes referred to as
"print chevron." In this form, the
first expression after the >> must
evaluate to a"file-like" object,
specifically an object that has a
write() method as described above.
With this extended form, the
subsequent expressions are printed to
this file object. If the first
expression evaluates to None, then
sys.stdout is used as the file for
output.


1
** Using sets to reference contents in sets of frozensets**

正如您可能知道的,集合是可变的,因此不可散列,因此,如果要生成一组集合(或将集合用作字典键),则需要使用frozenset:

1
2
3
4
5
>>> fabc = frozenset('abc')
>>> fxyz = frozenset('xyz')
>>> mset = set((fabc, fxyz))
>>> mset
{frozenset({'a', 'c', 'b'}), frozenset({'y', 'x', 'z'})}

但是,可以只使用普通集测试成员身份并删除/丢弃成员:

1
2
3
4
5
6
>>> abc = set('abc')
>>> abc in mset
True
>>> mset.remove(abc)
>>> mset
{frozenset({'y', 'x', 'z'})}

引用python标准库文档:

Note, the elem argument to the __contains__(), remove(), and discard()
methods may be a set. To support searching for an equivalent frozenset, the
elem set is temporarily mutated during the search and then restored. During
the search, the elem set should not be read or mutated since it does not
have a meaningful value.

不幸的是,或许令人吃惊的是,字典也并非如此:

1
2
3
4
5
6
7
>>> mdict = {fabc:1, fxyz:2}
>>> fabc in mdict
True
>>> abc in mdict
Traceback (most recent call last):
File"<interactive input>", line 1, in <module>
TypeError: unhashable type: 'set'


在布尔上下文对象

空元组,列表,和许多其他的转换,字符串对象是一个在布尔上下文(false等效和非等效"是一个真正的)。

1
2
3
4
5
6
7
empty_tuple = ()
empty_list = []
empty_dict = {}
empty_string = ''
empty_set = set()
if empty_tuple or empty_list or empty_dict or empty_string or empty_set:
  print 'Never happens!'

这允许一个逻辑操作,它返回到operands不是真/假,这是有用的在一些情况:

1
2
s = t or"Default value" # s will be assigned"Default value"
                         # if t is false/empty/none


功能支持。

生成器和生成器表达式,特别是。

Ruby再次成为这一主流,但Python也能做到这一点。库中没有Ruby那么普遍,Ruby太糟糕了,但是我更喜欢它的语法,它更简单。

因为它们并不是无所不在的,所以我没有看到那么多关于它们为什么有用的例子,但是它们允许我编写更干净、更高效的代码。


一次一屏打印多行字符串

site._Printer类中隐藏的不是真正有用的特性,它的license对象是一个实例。后者在调用时打印python许可证。可以创建同一类型的另一个对象,将字符串(例如文件的内容)作为第二个参数传递,并调用它:

1
type(license)(0,open('textfile.txt').read(),0)()

这将一次打印由若干行分割的文件内容:

1
2
3
4
5
6
...
file row 21
file row 22
file row 23

Hit Return for more, or q (and Return) to quit:


事实上,一切都是一个对象,因此是可扩展的。我可以将成员变量作为元数据添加到我定义的函数中:

1
2
3
4
>>> def addInts(x,y):
...    return x + y
>>> addInts.params = ['integer','integer']
>>> addInts.returnType = 'integer'

这对于编写动态单元测试非常有用,例如


私有方法和数据隐藏(封装)

在python中有一个常见的习惯用法,用来表示方法和其他类成员,这些方法和其他类成员的名称以下划线开头,并不打算成为类的外部API的一部分。这很方便,并且在实践中非常有效,但它给人的错误印象是,Python不支持私有代码和/或数据的真正封装。事实上,python自动为您提供了词汇闭包,这使得在实际情况需要时,以一种更加防弹的方式封装数据非常容易。下面是一个利用此技术的类的人为示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyClass(object):
  def __init__(self):

    privateData = {}

    self.publicData = 123

    def privateMethod(k):
      print privateData[k] + self.publicData

    def privilegedMethod():
      privateData['foo'] ="hello"
      privateMethod('foo')

    self.privilegedMethod = privilegedMethod

  def publicMethod(self):
    print self.publicData

这里有一个人为的使用例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> obj = MyClass()
>>> obj.publicMethod()
123
>>> obj.publicData = 'World'
>>> obj.publicMethod()
World
>>> obj.privilegedMethod()
hello World
>>> obj.privateMethod()
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute 'privateMethod'
>>> obj.privateData
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute 'privateData'

关键是,privateMethodprivateData根本不是obj的属性,因此它们不能从外部访问,也不能出现在dir()或类似文件中。它们是构造函数中的局部变量,在__init__之外完全不可访问。然而,由于闭包的魔力,它们实际上是每个实例的变量,与它们关联的对象具有相同的生存期,即使除了(在本例中)通过调用privilegedMethod无法从外部访问它们。通常,这种非常严格的封装是多余的,但有时它确实可以非常方便地保持API或命名空间的整洁。

在python 2.x中,拥有可变私有状态的唯一方法是使用可变对象(如本例中的dict)。许多人都说这有多烦人。python 3.x将通过引入pep 3104中描述的nonlocal关键字来消除这一限制。


测试密钥是否在dict中的简单方法:

1
2
3
4
5
6
7
8
>>> 'key' in { 'key' : 1 }
True

>>> d = dict(key=1, key2=2)
>>> if 'key' in d:
...     print 'Yup'
...
Yup


标准python中的spam模块

用于测试目的。

我从ctypes教程中选择了它。自己试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> import __hello__
Hello world...
>>> type(__hello__)
<type 'module'>
>>> from __phello__ import spam
Hello world...
Hello world...
>>> type(spam)
<type 'module'>
>>> help(spam)
Help on module __phello__.spam in __phello__:

NAME
    __phello__.spam

FILE
    c:\python26\<frozen>


类作为第一类对象(通过动态类定义显示)

注意闭包的使用。如果这个特殊的例子看起来像是解决问题的"正确"方法,请仔细重新考虑…好几次:)

1
2
3
4
5
6
7
8
9
10
def makeMeANewClass(parent, value):
  class IAmAnObjectToo(parent):
    def theValue(self):
      return value
  return IAmAnObjectToo

Klass = makeMeANewClass(str,"fred")
o = Klass()
print isinstance(o, str)  # => True
print o.theValue()        # => fred


不是一个隐藏的特性,而是一些有用的特性。

用于循环浏览列表对中的项

1
for x, y in zip(s, s[1:]):


1
2
3
4
>>> float('infinity')
inf
>>> float('NaN')
nan

更多信息:

  • http://docs.python.org/library/functions.html float
  • http://www.python.org/dev/peps/pep-0754/
  • python nan和inf值


关于Nick Johnson对属性类的实现(当然只是描述符的演示,而不是内置的替换),我将包括一个引发属性错误的setter:

1
2
3
4
5
6
7
8
9
10
11
class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

    def __set__(self, obj, value):
       raise AttributeError, 'Read-only attribute'

包含setter使其成为数据描述符,而不是方法/非数据描述符。数据描述符优先于实例字典。现在一个实例不能将不同的对象分配给属性名,并且尝试分配给属性会导致属性错误。


getattr内置函数:

1
2
3
4
5
6
7
8
9
10
>>> class C():
    def getMontys(self):
        self.montys = ['Cleese','Palin','Idle','Gilliam','Jones','Chapman']
        return self.montys


>>> c = C()
>>> getattr(c,'getMontys')()
['Cleese', 'Palin', 'Idle', 'Gilliam', 'Jones', 'Chapman']
>>>

如果要根据上下文分派函数,则非常有用。参见dive into python(此处)中的示例


内存管理

python动态分配内存并使用垃圾收集来恢复未使用的空间。一旦对象超出范围,并且没有其他变量引用它,它将被恢复。我不必担心缓冲区溢出和缓慢增长的服务器进程。内存管理也是其他动态语言的一个特性,但是Python做得很好。

当然,我们必须注意循环引用,并保持对不再需要的对象的引用,但是弱引用在这里有很大帮助。


完全不是隐藏的功能,但仍然很好:

1
2
3
import os.path as op

root_dir = op.abspath(op.join(op.dirname(__file__),".."))

操作路径时可保存大量字符!


曾经使用过xrange(int)而不是range(int)….它的内存使用率较低,并不真正依赖于整数的大小。哎呀!!不是很好吗?


如果在函数中使用exec,则变量查找规则会发生剧烈变化。闭包不再可能,但python允许在函数中使用任意标识符。这为您提供了一个"modifiable locals()"并可用于星型导入标识符。不利的是,它会使每次查找速度变慢,因为变量最终出现在dict中,而不是帧中的槽中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
>>> def f():
...  exec"a = 42"
...  return a
...
>>> def g():
...  a = 42
...  return a
...
>>> import dis
>>> dis.dis(f)
  2           0 LOAD_CONST               1 ('a = 42')
              3 LOAD_CONST               0 (None)
              6 DUP_TOP            
              7 EXEC_STMT          

  3           8 LOAD_NAME                0 (a)
             11 RETURN_VALUE        
>>> dis.dis(g)
  2           0 LOAD_CONST               1 (42)
              3 STORE_FAST               0 (a)

  3           6 LOAD_FAST                0 (a)
              9 RETURN_VALUE

不是编程功能,但在将python与bashshell scripts一起使用时非常有用。

1
python -c"import os; print(os.getcwd());"

请参见这里的python文档。在编写较长的Python脚本时需要注意的其他事项可以在本讨论中看到。


1
2
3
4
>>> x=[1,1,2,'a','a',3]
>>> y = [ _x for _x in x if not _x in locals()['_[1]'] ]
>>> y
[1, 2, 'a', 3]

"locals()["[1]"]是正在创建的列表的"秘密名称"。当正在构建的列表状态影响后续的构建决策时非常有用。


python的位置和关键字扩展可以即时使用,而不仅仅是从存储列表中使用。

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

对于这样的事情,它通常更有用:

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


使用map和reduce函数的map reduce

以这种方式创建一个简单的sumproduct:

1
2
def sumprod(x,y):
    return reduce(lambda a,b:a+b, map(lambda a, b: a*b,x,y))

例子:

1
2
In [2]: sumprod([1,2,3],[4,5,6])
Out[2]: 32


在python 2中,可以通过用反勾号将表达式括起来来生成表达式的字符串表示:

1
2
 >>> `sorted`
'<built-in function sorted>'

这在python 3.x中消失了。


脚本(和doctest字符串)的交互式调试

我不认为这是众所周知的,但是在任何Python脚本中添加这一行:

import pdb; pdb.set_trace()

将导致PDB调试器在代码中的该点弹出运行光标。我认为,更鲜为人知的是,你可以在一个医生测试中使用同一行:

1
2
3
4
5
"""
>>> 1 in (1,2,3)  
Becomes
>>> import pdb; pdb.set_trace(); 1 in (1,2,3)
"""

然后可以使用调试器签出doctest环境。您不能真正地单步执行doctest,因为每一行都是自动运行的,但是它是调试doctest全局和环境的一个很好的工具。


一些具有reduce和operator的酷特性。

1
2
3
4
5
6
7
8
9
10
11
>>> from operator import add,mul
>>> reduce(add,[1,2,3,4])
10
>>> reduce(mul,[1,2,3,4])
24
>>> reduce(add,[[1,2,3,4],[1,2,3,4]])
[1, 2, 3, 4, 1, 2, 3, 4]
>>> reduce(add,(1,2,3,4))
10
>>> reduce(mul,(1,2,3,4))
24

您可以根据需要构建一个函数Kwargs:

1
2
3
kwargs = {}
kwargs[str("%s__icontains" % field)] = some_value
some_function(**kwargs)

str()调用在某种程度上是必需的,因为python会抱怨它不是字符串。不知道为什么;)我将其用于Djangos对象模型中的动态过滤器:

1
result = model_class.objects.filter(**kwargs)

命令.getoutput

如果你想得到直接输出到stdoutstderr的函数的输出,就像os.system的情况一样,commands.getoutput来救援。整个模块都是很棒的。

1
2
3
4
>>> print commands.getoutput('ls')
myFile1.txt    myFile2.txt    myFile3.txt    myFile4.txt    myFile5.txt
myFile6.txt    myFile7.txt    myFile8.txt    myFile9.txt    myFile10.txt
myFile11.txt   myFile12.txt   myFile13.txt   myFile14.txt   module.py


将一个字符串相乘以使其重复

1
print"SO"*5

给予

1
SOSOSOSOSO


以下是调试类型错误时使用的一个有用函数

1
2
def typePrint(object):
    print(str(object) +" - (" + str(type(object)) +")")

例如,它只打印输入,然后打印类型

1
2
3
>>> a = 101
>>> typePrint(a)
    101 - (<type 'int'>)


1
2
for line in open('foo'):
    print(line)

这相当于(但更好的)以下内容:

1
2
3
4
f = open('foo', 'r')
for line in f.readlines():
   print(line)
f.close()


1
is_ok() and"Yes" or"No"

要激活接受它的IDE中的自动完成功能(如idle、editra、iep),而不是:"嗨"。(然后点击标签),你可以在IDE中作弊,只需嗨!(还有你的heat tab)(如你所见,开头没有单引号)因为它只会使用最新的标点符号,就像你添加时一样:点击enter,它会直接添加一个缩进,不知道它是否会更改,但它不再是提示。)


支撑

1
2
3
4
5
6
7
8
9
def g():
    print 'hi!'

def f(): (
    g()
)

>>> f()
hi!