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

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

快速链接到答案:

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


当前回答

函数参数解包

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

例如:

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)

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

其他回答

修饰符

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

暴露可变缓冲区

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

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

__getattr__ ()

getattr是一种创建泛型类的好方法,在编写API时尤其有用。例如,在FogBugz Python API中,getattr用于无缝地将方法调用传递给web服务:

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')时,他们实际上不会调用搜索方法。相反,getattr通过创建一个新函数来处理调用,该函数包装了makerequest方法,该方法将适当的HTTP请求发送给web API。任何错误都将由web服务分派并传递回用户。

“解包”到函数参数

def foo(a, b, c):
        print a, b, c

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

执行打印时:

3 14 15

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

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

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

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

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

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

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