Python
语法
- 类的
__init__()方法只能返回None;显式返回其他值会触发TypeError。 with EXPR as VAR:会先调用上下文管理器的__enter__(),并把它的返回值绑定到VAR;离开代码块时调用__exit__()。VAR在代码块结束后仍然存在,其类型由__enter__()的返回值决定。print(OBJ)优先使用OBJ.__str__()的结果;如果类型没有定义__str__(),则回退到__repr__()。
函数默认参数
默认参数在函数定义时求值一次,而不是在每次调用时重新求值。因此,不要把列表、字典、集合等可变对象直接用作默认值:
def add_item(item, items=[]):
items.append(item)
return items
print(add_item(1), add_item(2))
# [1, 2] [1, 2]
两次调用复用了同一个默认列表。print() 的参数会先从左到右完成求值;两个返回值又指向同一个列表,所以真正打印时它们都已经是 [1, 2]。
需要为每次调用创建新列表时,应使用 None 作为哨兵值:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
闭包与延迟绑定
闭包中的自由变量通常在函数被调用时查找,而不是在函数创建时复制其当前值,这称为延迟绑定(late binding):
funcs = [lambda: i for i in range(3)]
print(len(funcs))
# 3
print([func() for func in funcs])
# [2, 2, 2]
列表推导式创建了三个不同的函数对象,但它们都引用列表推导式作用域中的同一个 i。推导式结束后,该变量的最终值为 2,所以稍后调用三个函数时都得到 2。在 Python 3 中,这个 i 属于列表推导式自己的作用域,不会泄漏到外层作用域。
如果需要保存每轮循环当时的值,可以利用默认参数在函数定义时求值的特性:
funcs = [lambda value=i: value for i in range(3)]
print([func() for func in funcs])
# [0, 1, 2]
列表推导式与生成器表达式
把列表推导式外层的方括号换成圆括号,就得到生成器表达式:
# 列表推导式:立即创建三个函数并保存在列表中
funcs_list = [lambda value=i: value for i in range(3)]
# 生成器表达式:迭代时才逐个创建函数
funcs_generator = (lambda value=i: value for i in range(3))
print([func() for func in funcs_generator])
# [0, 1, 2]
列表会立即计算全部元素,可以按索引访问和重复遍历。生成器按需产生元素,通常只可消费一次,也不支持按索引访问;它适合不需要一次性把所有结果保存在内存中的场景。
Certifi
certifi 是一个 Python 库,旨在为 Python 项目提供 Mozilla 维护的受信任根证书合集(CA Bundle),确保 HTTPS 网络请求的安全。如果使用 mitmproxy debug,可能需要 export SSL_CERT_FILE=~/.mitmproxy/mitmproxy-ca-cert.pem 来信任相关证书。