Python编程语言中有哪些鲜为人知但很有用的特性?
尽量将答案限制在Python核心。
每个回答一个特征。
给出一个例子和功能的简短描述,而不仅仅是文档链接。
使用标题作为第一行标记该特性。
快速链接到答案:
参数解包
牙套
链接比较运算符
修饰符
可变默认参数的陷阱/危险
描述符
字典默认的.get值
所以测试
省略切片语法
枚举
其他/
函数作为iter()参数
生成器表达式
导入该
就地值交换
步进列表
__missing__物品
多行正则表达式
命名字符串格式化
嵌套的列表/生成器推导
运行时的新类型
.pth文件
ROT13编码
正则表达式调试
发送到发电机
交互式解释器中的制表符补全
三元表达式
试着/ / else除外
拆包+打印()函数
与声明
私有方法和数据隐藏(封装)
在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关键字来消除此限制。
在子类中扩展属性(定义为描述符)
有时扩展(修改)子类中描述符“返回”的值是有用的。使用super()可以轻松完成:
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选项执行脚本并允许您以交互模式继续):
>>> B().prop
{'a': 1, 'b': 2}
就地值交换
>>> a = 10
>>> b = 5
>>> a, b
(10, 5)
>>> a, b = b, a
>>> a, b
(5, 10)
赋值语句的右边是一个表达式,用于创建一个新的元组。赋值的左边立即将(未引用的)元组解包为名称a和b。
赋值之后,新的元组不被引用,并标记为垃圾收集,绑定到a和b的值已经交换。
正如Python教程中关于数据结构的部分所述,
注意,多重赋值实际上只是元组打包和序列解包的组合。
** Using sets to reference contents in sets of frozensets**
正如你可能知道的,集合是可变的,因此是不可哈希的,所以如果你想创建一个集合的集合(或使用集合作为字典的键),使用frozensets是必要的:
>>> fabc = frozenset('abc')
>>> fxyz = frozenset('xyz')
>>> mset = set((fabc, fxyz))
>>> mset
{frozenset({'a', 'c', 'b'}), frozenset({'y', 'x', 'z'})}
然而,仅仅使用普通集合就可以测试成员并删除/丢弃成员:
>>> abc = set('abc')
>>> abc in mset
True
>>> mset.remove(abc)
>>> mset
{frozenset({'y', 'x', 'z'})}
引用Python标准库文档:
注意,__contains__(), remove()和discard()的elem参数
方法可以是一个集合。为了支持搜索等价的frozenset,可以使用
Elem集在搜索过程中临时突变,然后恢复。在
搜索,elem集不应该被读取或改变,因为它没有
拥有有意义的价值。
不幸的是,也许是令人惊讶的是,字典并非如此:
>>> 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'