Python的隐藏功能

问题:Python的隐藏功能

Python编程语言鲜为人知但有用的功能是什么?

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

答案的快速链接:

What are the lesser-known but useful features of the Python programming language?

  • Try to limit answers to Python core.
  • One feature per answer.
  • Give an example and short description of the feature, not just a link to documentation.
  • Label the feature using a title as the first line.

Quick links to answers:


回答 0

链接比较运算符:

>>> 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 < x * 10 and x*10 < 100,但键入和每个输入较少该术语仅评估一次。

Chaining comparison operators:

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

In case you’re thinking it’s doing 1 < x, which comes out as True, and then comparing True < 10, which is also True, then no, that’s really not what happens (see the last example.) It’s really translating into 1 < x and x < 10, and x < 10 and 10 < x * 10 and x*10 < 100, but with less typing and each term is only evaluated once.


回答 1

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

正则表达式是python的一个很棒的功能,但是调试它们可能会很麻烦,而且很容易使正则表达式出错。

幸运的是,python可以通过将未记录的实验性隐藏标记re.DEBUG(实际上是128)传递给,从而输出正则表达式分析树re.compile

>>> 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]

当然,您可以将其与所需的任何标志(例如带注释的正则表达式)结合使用:

>>> 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)

Get the python regex parse tree to debug your regex.

Regular expressions are a great feature of python, but debugging them can be a pain, and it’s all too easy to get a regex wrong.

Fortunately, python can print the regex parse tree, by passing the undocumented, experimental, hidden flag re.DEBUG (actually, 128) to re.compile.

>>> 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

Once you understand the syntax, you can spot your errors. There we can see that I forgot to escape the [] in [/font].

Of course you can combine it with whatever flags you want, like commented regexes:

>>> 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)

回答 2

枚举

用enumerate包装一个可迭代对象,它将产生该项目及其索引。

例如:


>>> 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
>>>

参考文献:

enumerate

Wrap an iterable with enumerate and it will yield the item along with its index.

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
>>>

References:


回答 3

创建生成器对象

如果你写

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

您可以找出生成器并将其分配给x。现在,这意味着您可以

for n in x:

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

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

在某些情况下,这可能会导致速度显着提高。

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

>>> 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)

Creating generators objects

If you write

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

you can get out the generator and assign it to x. Now it means you can do

for n in x:

The advantage of this is that you don’t need intermediate storage, which you would need if you did

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

In some cases this can lead to significant speed up.

You can append many if statements to the end of the generator, basically replicating nested for loops:

>>> 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)

回答 4

iter()可以接受可调用参数

例如:

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

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

iter() can take a callable argument

For instance:

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

The iter(callable, until_value) function repeatedly calls callable and yields its result until until_value is returned.


回答 5

注意可变的默认参数

>>> def foo(x=[]):
...     x.append(1)
...     print x
... 
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

相反,您应该使用表示“未给定”的前哨值,并默认将其替换为您想要的可变变量:

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

Be careful with mutable default arguments

>>> def foo(x=[]):
...     x.append(1)
...     print x
... 
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

Instead, you should use a sentinel value denoting “not given” and replace with the mutable you’d like as default:

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

回答 6

将值发送到生成器函数中。例如,具有以下功能:

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

您可以:

>>> 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

Sending values into generator functions. For example having this function:

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

You can:

>>> 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

回答 7

如果您不喜欢使用空格来表示作用域,则可以通过发出以下命令来使用C样式的{}:

from __future__ import braces

If you don’t like using whitespace to denote scopes, you can use the C-style {} by issuing:

from __future__ import braces

回答 8

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

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

特殊情况x[::-1]是“ x反转”的有用成语。

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

The step argument in slice operators. For example:

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

The special case x[::-1] is a useful idiom for ‘x reversed’.

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

回答 9

装饰工

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

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

>>> 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

Decorators

Decorators allow to wrap a function or method in another function that can add functionality, modify arguments or results, etc. You write decorators one line above the function definition, beginning with an “at” sign (@).

Example shows a print_args decorator that prints the decorated function’s arguments before calling it:

>>> 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

回答 10

for … else语法(请参阅http://docs.python.org/ref/for.html

for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

除非调用break,否则“ else”块通常会在for循环的末尾执行。

上面的代码可以模拟如下:

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

The for…else syntax (see http://docs.python.org/ref/for.html )

for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

The “else” block will be normally executed at the end of the for loop, unless the break is called.

The above code could be emulated as follows:

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

回答 11

从2.5开始,字典有一个特殊的方法__missing__用于缺失项的调用:

>>> 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调用defaultdict中还有一个dict子类,它的功能几乎相同,但是为不存在的项目调用不带参数的函数:

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

我建议在将此类字典传递给不希望此类子类的函数之前,将其转换为常规字典。许多代码使用d[a_key]并捕获KeyErrors来检查是否存在某个项目,从而将新项目添加到dict中。

From 2.5 onwards dicts have a special method __missing__ that is invoked for missing items:

>>> 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]}

There is also a dict subclass in collections called defaultdict that does pretty much the same but calls a function without arguments for not existing items:

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

I recommend converting such dicts to regular dicts before passing them to functions that don’t expect such subclasses. A lot of code uses d[a_key] and catches KeyErrors to check if an item exists which would add a new item to the dict.


回答 12

就地价值交换

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

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

分配的右侧是创建新元组的表达式。作业的左侧立即将(未引用的)元组解压缩到名称ab

分配后,新的元组将不被引用并标记为垃圾回收,并且值绑定到a并且b已经交换。

Python教程中有关数据结构的部分所述

注意,多重分配实际上只是元组打包和序列拆包的组合。

In-place value swapping

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

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

The right-hand side of the assignment is an expression that creates a new tuple. The left-hand side of the assignment immediately unpacks that (unreferenced) tuple to the names a and b.

After the assignment, the new tuple is unreferenced and marked for garbage collection, and the values bound to a and b have been swapped.

As noted in the Python tutorial section on data structures,

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


回答 13

可读的正则表达式

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

详细语法示例(从Dive into 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})$"

Readable regular expressions

In Python you can split a regular expression over multiple lines, name your matches and insert comments.

Example verbose syntax (from Dive into 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)

Example naming matches (from Regular Expression HOWTO)

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

You can also verbosely write a regex without using re.VERBOSE thanks to string literal concatenation.

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

回答 14

函数参数解压缩

您可以使用*和将列表或字典作为函数参数解压缩**

例如:

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)

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

Function argument unpacking

You can unpack a list or a dictionary as function arguments using * and **.

For example:

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)

Very useful shortcut since lists, tuples and dicts are widely used as containers.


回答 15

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

#!/usr/bin/env python
# -*- coding: rot13 -*-

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

ROT13 is a valid encoding for source code, when you use the right coding declaration at the top of the code file:

#!/usr/bin/env python
# -*- coding: rot13 -*-

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

回答 16

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

>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"

完全一样

>>> class NewType(object):
>>>     x = "hello"
>>> n = NewType()
>>> n.x
"hello"

可能不是最有用的东西,但很高兴知道。

编辑:新类型的固定名称,应NewType与with class语句完全相同。

编辑:调整标题以更准确地描述功能。

Creating new types in a fully dynamic manner

>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"

which is exactly the same as

>>> class NewType(object):
>>>     x = "hello"
>>> n = NewType()
>>> n.x
"hello"

Probably not the most useful thing, but nice to know.

Edit: Fixed name of new type, should be NewType to be the exact same thing as with class statement.

Edit: Adjusted the title to more accurately describe the feature.


回答 17

上下文管理器和“ with”语句

PEP 343中引入的上下文管理器是一个对象,它充当一组语句的运行时上下文。

由于该功能使用了新的关键字,因此逐步引入了该功能:通过__future__指令在Python 2.5中可用。Python 2.6及更高版本(包括Python 3)默认情况下可用。

我经常使用“ with”语句,因为我认为这是一个非常有用的结构,下面是一个快速演示:

from __future__ import with_statement

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

在幕后发生的事情是,“ with”语句调用了文件对象上的special __enter____exit__method。__exit__如果with语句主体引发了任何异常,则异常详细信息也将传递到该异常,从而允许在那里进行异常处理。

在这种特殊情况下,这为您执行的操作是,它保证在执行超出with套件范围时关闭文件,无论是正常发生还是引发异常。从根本上讲,它是一种抽象通用异常处理代码的方法。

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

Context managers and the “with” Statement

Introduced in PEP 343, a context manager is an object that acts as a run-time context for a suite of statements.

Since the feature makes use of new keywords, it is introduced gradually: it is available in Python 2.5 via the __future__ directive. Python 2.6 and above (including Python 3) has it available by default.

I have used the “with” statement a lot because I think it’s a very useful construct, here is a quick demo:

from __future__ import with_statement

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

What’s happening here behind the scenes, is that the “with” statement calls the special __enter__ and __exit__ methods on the file object. Exception details are also passed to __exit__ if any exception was raised from the with statement body, allowing for exception handling to happen there.

What this does for you in this particular case is that it guarantees that the file is closed when execution falls out of scope of the with suite, regardless if that occurs normally or whether an exception was thrown. It is basically a way of abstracting away common exception-handling code.

Other common use cases for this include locking with threads and database transactions.


回答 18

字典具有get()方法

字典有一个“ get()”方法。如果执行d [‘key’]而键不存在,则会出现异常。如果执行d.get(’key’),则如果’key’不存在,则返回None。您可以添加第二个参数来取回该项目,而不是无,例如:d.get(’key’,0)。

这非常适合诸如加号之类的事情:

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

Dictionaries have a get() method

Dictionaries have a ‘get()’ method. If you do d[‘key’] and key isn’t there, you get an exception. If you do d.get(‘key’), you get back None if ‘key’ isn’t there. You can add a second argument to get that item back instead of None, eg: d.get(‘key’, 0).

It’s great for things like adding up numbers:

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


回答 19

描述符

它们是一大堆Python核心功能背后的魔力。

当您使用点分访问来查找成员(例如xy)时,Python首先在实例字典中查找该成员。如果找不到,它将在类字典中查找。如果它在类字典中找到它,并且该对象实现了描述符协议,而不是仅仅返回它,Python就会执行它。一个描述符是实现任何类__get____set____delete__方法。

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

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)

您将像内置的property()一样使用它:

class MyClass(object):
    @Property
    def foo(self):
        return "Foo!"

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

Raymond Hettinger 的教程很棒,比我做得更好。

Descriptors

They’re the magic behind a whole bunch of core Python features.

When you use dotted access to look up a member (eg, x.y), Python first looks for the member in the instance dictionary. If it’s not found, it looks for it in the class dictionary. If it finds it in the class dictionary, and the object implements the descriptor protocol, instead of just returning it, Python executes it. A descriptor is any class that implements the __get__, __set__, or __delete__ methods.

Here’s how you’d implement your own (read-only) version of property using descriptors:

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)

and you’d use it just like the built-in property():

class MyClass(object):
    @Property
    def foo(self):
        return "Foo!"

Descriptors are used in Python to implement properties, bound methods, static methods, class methods and slots, amongst other things. Understanding them makes it easy to see why a lot of things that previously looked like Python ‘quirks’ are the way they are.

Raymond Hettinger has an excellent tutorial that does a much better job of describing them than I do.


回答 20

条件分配

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

它确实听起来像:“如果y为1,则将3分配给x,否则将2分配给x”。请注意,不需要括号,但是出于可读性考虑,我喜欢它们。如果您有更复杂的东西,也可以将其链接起来:

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

尽管在某个时候,它有点太过分了。

请注意,您可以在任何表达式中使用if … else。例如:

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

如果y为1,则调用func1,否则调用func2。在这两种情况下,将使用参数arg1和arg2调用相应的函数。

类似地,以下内容也有效:

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

其中class1和class2是两个类。

Conditional Assignment

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

It does exactly what it sounds like: “assign 3 to x if y is 1, otherwise assign 2 to x”. Note that the parens are not necessary, but I like them for readability. You can also chain it if you have something more complicated:

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

Though at a certain point, it goes a little too far.

Note that you can use if … else in any expression. For example:

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

Here func1 will be called if y is 1 and func2, otherwise. In both cases the corresponding function will be called with arguments arg1 and arg2.

Analogously, the following is also valid:

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

where class1 and class2 are two classes.


回答 21

Doctest:同时进行文档编制和单元测试。

从Python文档中提取的示例:

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()

Doctest: documentation and unit-testing at the same time.

Example extracted from the Python documentation:

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()

回答 22

命名格式

%-formatting需要一个字典(也适用于%i /%s等。验证)。

>>> 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()也是一个字典,因此您可以简单地将其作为字典传递,并从本地变量中获取%替换。我认为这是不满意的,但可以简化。

新样式格式

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

Named formatting

% -formatting takes a dictionary (also applies %i/%s etc. validation).

>>> 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.

And since locals() is also a dictionary, you can simply pass that as a dict and have % -substitions from your local variables. I think this is frowned upon, but simplifies things..

New Style Formatting

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

回答 23

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

“ [修改python搜索路径的最方便的方法是将路径配置文件添加到Python路径上已经存在的目录中,通常是… / site-packages /目录。路径配置文件的扩展名为.pth。 ,并且每行必须包含一个附加到sys.path的路径。(由于新路径附加到sys.path,因此添加目录中的模块不会覆盖标准模块。这意味着您不能使用此机制用于安装标准模块的固定版本。)”

To add more python modules (espcially 3rd party ones), most people seem to use PYTHONPATH environment variables or they add symlinks or directories in their site-packages directories. Another way, is to use *.pth files. Here’s the official python doc’s explanation:

“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.)”


回答 24

exceptionselse子句:

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

Exception else clause:

try:
  put_4000000000_volts_through_it(parrot)
except Voom:
  print "'E's pining!"
else:
  print "This parrot is no more!"
finally:
  end_sketch()

The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try … except statement.

See http://docs.python.org/tut/node10.html


回答 25

重新引发异常

# 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一样通过“回溯”模块完成打印。

Re-raising exceptions:

# 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)

The ‘raise’ statement with no arguments inside an error handler tells Python to re-raise the exception with the original traceback intact, allowing you to say “oh, sorry, sorry, I didn’t mean to catch that, sorry, sorry.”

If you wish to print, store or fiddle with the original traceback, you can get it with sys.exc_info(), and printing it like Python would is done with the ‘traceback’ module.


回答 26

主要信息:)

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

解密

提姆·彼得斯(Tim Peters)撰写的《 Python之禅》

美丽胜于丑陋。
显式胜于隐式。
简单胜于复杂。
复杂胜于复杂。
扁平比嵌套更好。
稀疏胜于密集。
可读性很重要。
特殊情况还不足以打破规则。
尽管实用性胜过纯度。
错误绝不能默默传递。
除非明确地保持沉默。
面对模棱两可的想法,拒绝猜测的诱惑。应该有一种-最好只有一种-显而易见的方法。
尽管除非您是荷兰人,否则一开始这种方式可能并不明显。
现在总比没有好。
虽然从来没有比这更好正确的现在。
如果实现难以解释,那是个坏主意。
如果实现易于解释,则可能是个好主意。
命名空间是一个很棒的主意-让我们做更多这些吧!

Main messages :)

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

De-cyphered:

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!


回答 27

交互式口译员选项卡完成

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环境变量。

Interactive Interpreter Tab Completion

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()

You will also have to set a PYTHONSTARTUP environment variable.


回答 28

嵌套列表推导和生成器表达式:

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

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

Nested list comprehensions and generator expressions:

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

These can replace huge chunks of nested-loop code.


回答 29

set内置运算符重载:

>>> 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}

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

Operator overloading for the set builtin:

>>> 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}

More detail from the standard library reference: Set Types