原始字符串(raw strings)
原始字符串的产生正是由于有正则表达式的存在。原因是 ASCII 字符和正则表达式特殊字符间所产生的冲突。比如,特殊符号“\b”在ASCII 字符中代表退格键, 但同时 “\b”也是一个正则表达式的特殊符号, 代表 “匹配一个单词边界”。为了让 RE 编译器把两个字符“\b”当成你想要表达的字符串,而不是一个退格键,你需要用另一个反斜线对它进行转义,即可以这样写:“\b”。
但这样做会把问题复杂化,特别是当你的正则表达式字符串里有很多特殊字符时,就更容易令人困惑了。在第六章,我们曾介绍过原始字符串,它经常被用于简化正则表达式的复杂程度。事实上,很多 Python 程序员在定义正则表达式时都只使用原始字符串。
下面的例子用来说明退格键 “\b” 和正则表达式 “\b”(包含或不包含原始字符串)之间的区别:
m = re.match('\bblow', 'blow') #退格键,没有匹配
if m is not None: m.group()
...
m = re.match('\\bblow', 'blow') #用\转义后,现在匹配了
if m is not None: m.group()
...
'blow'
m = re.match(r'\bblow', 'blow') #改用原始字符串
if m is not None: m.group()
...
'blow'
你可能注意到我们在正则表达式里使用“\d”,没用原始字符串,也没出现什么问题。那是因为ASCII 里没有对应的特殊字符,所以正则表达式编译器能够知道你指的是一个十进制数字。
python3编码
对于python3,默认的编码类型为unicode,即当写下语句 my_str = ‘my_str’ 时, my_str保存的是经过utf-8 编码的数据.
当你想对其做一些流操作,比如socket.sendall()这种,因为网络IO只支持字节流,所以要使用 my_str_en = my_str.encode()将其编码为符合utf-8 规范的字节流, 对方接收后,即可使用 my_str_en.decode()将字节流解码
生成器(generator)
对于一个generator, 可以使用next()方法获取下一个值,直至最后抛出StopIteration错误,但通常使用for循环来迭代
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
这是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
>>> g = fib(6)
>>> while True:
... try:
... x = next(g)
... print('g:', x)
... except StopIteration as e:
... print('Generator return value:', e.value)
... break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
你可能会问,为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
偏函数
把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单
int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数
int2('10010')
相当于
kw = { 'base': 2 }
int('10010', **kw)
##########################
max2 = functools.partial(max, 10)
实际上会把10作为*args的一部分自动加到左边,也就是:
max2(5, 6, 7)
相当于
args = (10, 5, 6, 7)
max(*args)