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

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

快速链接到答案:

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


当前回答

Monkeypatching对象

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

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

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

class struct(object):
    def __init__(**kwargs):
       self.__dict__.update(kwargs)

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

其他回答

Re-raising例外:

# 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在原始回溯完整的情况下重新引发异常,允许你说“哦,对不起,对不起,我不是有意捕捉那个,对不起,对不起。”

如果你想打印、存储或修改原始的traceback,你可以使用sys.exc_info()来获取它,并且像Python一样使用'traceback'模块来打印它。

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

不是真正的隐藏特性,但是partial对于函数的后期计算非常有用。

你可以在初始调用中绑定尽可能多的或尽可能少的参数到你想要的partial,并在以后使用任何剩余的参数调用它(在这个例子中,我已经将begin/end参数绑定到range,但第二次使用step arg调用它)

请参见文档。

修饰符

装饰器允许将一个函数或方法包装在另一个函数中,该函数可以添加功能、修改参数或结果等。在函数定义的上方一行编写装饰符,以“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

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

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

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

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

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

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

按以下方式访问字典元素 属性(属性)。所以如果 a1=AttrDict()有键'name' -> 而不是a1['name'],我们可以很容易 使用->访问a1的名称属性 a1.name


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