Python标准库学习笔记3:算法
1. functools---管理函数的工具
作用:处理其他函数的函数
Python版本:2.5及以后版本
functools模块提供了一些工具来调整或扩展函数和其他可回调对象,而不必完全重写.
1. 修饰符
functools模块提供的主要工具是partial类,它可以用来"包装"一个有默认参数的可回调对象.得到的对象本身是可回调的,可以看作就像是原来的函数.它与原函数的参数完全相同,调用时也可以提供额外的位置或命名参数.可以使用partial而不是lambda为函数提供默认参数,有些参数可以不指定.
partial对象
partial对象实际上可以理解为"C++的仿函数",JavaScript的curry化,和Python本身的装饰器功能类似,但更强大:
import functools
def myfunc(a, b = 2):
print ' called myfunc with:', (a, b)
return
def show_details(name, f, is_partial = False):
print '%s:' % name
print ' object:', f
if not is_partial:
print ' __name__:', f.__name__
if is_partial:
print ' func:', f.func
print ' args:', f.args
print ' keywords:', f.keywords
return
show_details('myfunc', myfunc)
myfunc('a', 3)
print
#set a different default value for 'b', but require
#the caller to provide 'a'
p1 = functools.partial(myfunc, b = 4)
show_details('partial with named default', p1, True)
p1('passing a')
p1('override b', b = 5)
print
#set default value for both 'a' and 'b'
p2 = functools.partial(myfunc, 'default a', b = 99)
show_details('partial with defaults', p2, True)
p2()
p2(b = 'override b')
print
print 'Insufficient argument:'
p1()
解释器显示如下:
>>>
myfunc:
object: <function myfunc at 0x00000000021B49E8>
__name__: myfunc
called myfunc with: ('a', 3)
partial with named default:
object: <functools.partial object at 0x00000000027AD638>
func: <function myfunc at 0x00000000021B49E8>
args: ()
keywords: {'b': 4}
called myfunc with: ('passing a', 4)
called myfunc with: ('override b', 5)
partial with defaults:
object: <functools.partial object at 0x00000000027AD688>
func: <function myfunc at 0x00000000021B49E8>
args: ('default a',)
keywords: {'b': 99}
called myfunc with: ('default a', 99)
called myfunc with: ('default a', 'override b')
Insufficient argument:
Traceback (most recent call last):
File "C:\Python27\test.py", line 38, in <module>
p1()
TypeError: myfunc() takes at least 1 argument (1 given)
而一个简单的装饰器实例如下:
def show(num):
def oneFunc(func):
def childFunc(name):
num.append(name)
print("num is")
print(num)
return childFunc
return oneFunc
@show([1, 2, 3])
def func(name):
return name
func("hello")
解释器显示如下:
>>>
num is
[1, 2, 3, 'hello']
获取函数属性
默认情况下,partial对象没有__name__或__doc__属性.如果没有这些属性,修饰的函数将更难调试.使用update_wrapper()可以从原函数将属性复制或添加到partial对象.
import functools
def myfunc(a, b = 2):
"""Docstring for myfunc()."""
print ' called myfunc with:', (a, b)
return
def show_details(name, f):
"""Show details of a callable object."""
print '%s:' % name
print ' object:', f
print ' __name__:',
try:
print f.__name__
except AttributeError:
print '(no __name__)'
print ' __doc__', repr(f.__doc__)
print
return
show_details('myfunc', myfunc)
p1 = functools.partial(myfunc, b = 4)
show_details('raw wrapper', p1)
print 'Updating wrapper:'
print ' assign:', functools.WRAPPER_ASSIGNMENTS
print ' update:', functools.WRAPPER_UPDATES
print
functools.update_wrapper(p1, myfunc)
show_details('updated wrapper', p1)
解释器显示如下:
>>>
myfunc:
object: <function myfunc at 0x00000000021449E8>
__name__: myfunc
__doc__ 'Docstring for myfunc().'
raw wrapper:
object: <functools.partial object at 0x00000000028ED638>
__name__: (no __name__)
__doc__ 'partial(func, *args, **keywords) - new function with partial application\n of the given arguments and keywords.\n'
Updating wrapper:
assign: ('__module__', '__name__', '__doc__')
update: ('__dict__',)
updated wrapper:
object: <functools.partial object at 0x00000000028ED638>
__name__: myfunc
__doc__ 'Docstring for myfunc().'
其他可回调对象
Partial适用于任何可回调对象,而不只是单独的函数
import functools
class MyClass(object):
"""Demonstration class for functools"""
def method1(self, a, b = 2):
"""Docstring for method1()."""
print ' called method1 with:', (self, a, b)
return
def method2(self, c, d = 5):
"""Docstring for method2()."""
print ' called method2 with:', (self, c, d)
return
wrapped_method2 = functools.partial(method2, 'wrapped c')
functools.update_wrapper(wrapped_method2, method2)
def __call__(self, e, f = 6):
"""Docstring for MyClass.__call__"""
print ' called object with:', (self, e, f)
return
def show_details(name, f):
"""Show details of a callable object."""
print '%s:' % name
print ' object:', f
print ' __name__:',
try:
print f.__name__
except AttributeError:
print '(no __name__)'
print ' __doc__', repr(f.__doc__)
return
o = MyClass()
#由类对象来创建实例,调用其方法method1
show_details('method1 straight', o.method1)
o.method1('no default for a', b = 3)
print
p1 = functools.partial(o.method1, b = 4)
functools.update_wrapper(p1, o.method1)
show_details('method1 wrapper', p1)
p1('a goes here')
print
show_details('method2', o.method2)
o.method2('no default for c', d = 6)
print
#wrapped_method2在内部已经实现了update_wrapper操作
show_details('wrapped method2', o.wrapped_method2)
o.wrapped_method2('no default for c', d = 6)
print
#由类名来创建实例
show_details('instance', o)
o('no default for e')
print
p2 = functools.partial(o, f = 7)
show_details('instance wrapper', p2)
p2('e goes here')
解释器显示如下:
>>>
method1 straight:
object: <bound method MyClass.method1 of <__main__.MyClass object at 0x00000000028809E8>>
__name__: method1
__doc__ 'Docstring for method1().'
called method1 with: (<__main__.MyClass object at 0x00000000028809E8>, 'no default for a', 3)
method1 wrapper:
object: <functools.partial object at 0x000000000287D728>
__name__: method1
__doc__ 'Docstring for method1().'
called method1 with: (<__main__.MyClass object at 0x00000000028809E8>, 'a goes here', 4)
method2:
object: <bound method MyClass.method2 of <__main__.MyClass object at 0x00000000028809E8>>
__name__: method2
__doc__ 'Docstring for method2().'
called method2 with: (<__main__.MyClass object at 0x00000000028809E8>, 'no default for c', 6)
wrapped method2:
object: <functools.partial object at 0x000000000287D688>
__name__: method2
__doc__ 'Docstring for method2().'
called method2 with: ('wrapped c', 'no default for c', 6)
instance:
object: <__main__.MyClass object at 0x00000000028809E8>
__name__: (no __name__)
__doc__ 'Demonstration class for functools'
called object with: (<__main__.MyClass object at 0x00000000028809E8>, 'no default for e', 6)
instance wrapper:
object: <functools.partial object at 0x000000000287D778>
__name__: (no __name__)
__doc__ 'partial(func, *args, **keywords) - new function with partial application\n of the given arguments and keywords.\n'
called object with: (<__main__.MyClass object at 0x00000000028809E8>, 'e goes here', 7)
为修饰符获取函数属性
在修饰符中使用时,更新包装的可回调对象的属性尤其有用,因为变换后的函数最后会得到原'裸'函数的属性.
import functools
def show_details(name, f):
"""Show details of a callable object."""
print '%s:' % name
print ' object:', f
print ' __name__:',
try:
print f.__name__
except AttributeError:
print '(no __name__)'
print ' __doc__', repr(f.__doc__)
print
return
def simple_decorator(f):
#装饰器起作用:这里decorated实际上等价于wraps(decorated)函数
@functools.wraps(f)
def decorated(a = 'decorated defaults', b = 1):
print ' decorated:', (a, b)
print ' ',
f(a, b = b)
return
return decorated
def myfunc(a, b = 2):
"""myfunc() is not complicated"""
print ' myfunc:', (a, b)
return
#the raw function
show_details('myfunc', myfunc)
myfunc('unwrapped, default b')
myfunc('unwrapped, passing b', 3)
print
#wrap explicitly
wrapped_myfunc = simple_decorator(myfunc)
show_details('wrapped_myfunc', wrapped_myfunc)
wrapped_myfunc()
wrapped_myfunc('args to wrapped', 4)
print
#wrap with decorator syntax
@simple_decorator
def decorated_myfunc(a, b):
"""decorated_myfunc function"""
myfunc(a, b)
return
show_details('decorated_myfunc', decorated_myfunc)
decorated_myfunc()
decorated_myfunc('args to decorated', 4)
解释器显示如下:
>>>
myfunc:
object: <function myfunc at 0x00000000028427B8>
__name__: myfunc
__doc__ 'myfunc() is not complicated'
myfunc: ('unwrapped, default b', 2)
myfunc: ('unwrapped, passing b', 3)
wrapped_myfunc:
object: <function myfunc at 0x0000000002842828>
__name__: myfunc
__doc__ 'myfunc() is not complicated'
decorated: ('decorated defaults', 1)
myfunc: ('decorated defaults', 1)
decorated: ('args to wrapped', 4)
myfunc: ('args to wrapped', 4)
decorated_myfunc:
object: <function decorated_myfunc at 0x0000000002842908>
__name__: decorated_myfunc
__doc__ 'decorated_myfunc function'
decorated: ('decorated defaults', 1)
myfunc: ('decorated defaults', 1)
decorated: ('args to decorated', 4)
myfunc: ('args to decorated', 4)
备注:
1. functools提供了一个修饰符wraps(),它会对所修饰的函数应用update_wrapper().
2. 需要深入理解装饰器,才能理解以上代码.
2. 比较
富比较
设计富比较API是为了支持涉及复杂比较的类,从而以最高效的方式实现各个测试:
import functools
import inspect
from pprint import pprint
@functools.total_ordering
class MyObject(object):
def __init__(self, val):
self.val = val
def __eq__(self, other):
print ' testing __eq__(%s, %s)' % (self.val, other.val)
return self.val == other.val
def __gt__(self, other):
print ' testing __gt__(%s, %s)' % (self.val, other.val)
return self.val > other.val
print 'Methods:\n'
pprint(inspect.getmembers(MyObject, inspect.ismethod))
a = MyObject(1)
b = MyObject(2)
print '\nComparisons:'
for expr in ['a < b', 'a <= b', 'a == b', 'a >= b', 'a > b']:
print '\n%-6s:' % expr
result = eval(expr)
print ' result of %s: %s' % (expr, result)
解释器显示如下:
>>>
Methods:
[('__eq__', <unbound method MyObject.__eq__>),
('__ge__', <unbound method MyObject.__ge__>),
('__gt__', <unbound method MyObject.__gt__>),
('__init__', <unbound method MyObject.__init__>),
('__le__', <unbound method MyObject.__le__>),
('__lt__', <unbound method MyObject.__lt__>)]
Comparisons:
a < b :
testing __gt__(1, 2)
testing __eq__(1, 2)
result of a < b: True
a <= b:
testing __gt__(1, 2)
result of a <= b: True
a == b:
testing __eq__(1, 2)
result of a == b: False
a >= b:
testing __gt__(1, 2)
testing __eq__(1, 2)
result of a >= b: False
a > b :
testing __gt__(1, 2)
result of a > b: False
比对序
由于在Python3中不用cmp,所以我们需要使用cmp_to_key对原cmp函数进行转换:
import functools
class MyObject(object):
def __init__(self, val):
self.val = val
def __str__(self):
return 'MyObject(%s)' % self.val
def compare_obj(a, b):
"""old-style comparison function."""
print 'comparing %s and %s' % (a, b)
return cmp(a.val, b.val)
#Make a key function using cmp_to_key()
get_key = functools.cmp_to_key(compare_obj)
def get_key_wrapper(o):
"""Wrapper function for get_key to allow for print statements"""
new_key = get_key(o)
print 'key_wrapper(%s) -> %s' % (o, new_key)
return new_key
objs = [MyObject(x) for x in range(5, 0, -1)]
for o in sorted(objs, key=get_key_wrapper):
print o
解释器显示如下:
>>>
key_wrapper(MyObject(5)) -> <functools.K object at 0x0000000002564798>
key_wrapper(MyObject(4)) -> <functools.K object at 0x00000000027CF198>
key_wrapper(MyObject(3)) -> <functools.K object at 0x00000000027CFA08>
key_wrapper(MyObject(2)) -> <functools.K object at 0x00000000027CF1F8>
key_wrapper(MyObject(1)) -> <functools.K object at 0x00000000027CF258>
comparing MyObject(4) and MyObject(5)
comparing MyObject(3) and MyObject(4)
comparing MyObject(2) and MyObject(3)
comparing MyObject(1) and MyObject(2)
MyObject(1)
MyObject(2)
MyObject(3)
MyObject(4)
MyObject(5)
2. itertools---迭代器函数
作用:itertools模块包含一组函数用于处理序列数据集
Python版本:2.3及以后版本
与使用列表的代码相比,基于迭代器的算法可以提供更好的内存使用特性.在真正需要数据之前,并不从迭代器生成数据,由于这个原因,不需要将所有数据都同时存储在内存中.这种"懒"处理模型可以减少内存使用,相应的还可以减少交换以及大数据集的其他副作用,从而改善性能.
1. 合并和分解迭代器
chain函数取多个迭代器作为参数,最后返回一个迭代器,它能生成所有输入迭代器的内容,就好像这些内容来自一个迭代器一样.
利用chain(),可以轻松的处理多个序列而不必构造一个大的列表.
>>> from itertools import *
>>> for i in chain([1, 2, 3], ['a', 'b', 'c']):
print i,
1 2 3 a b c
izip()返回一个迭代器,它会把多个迭代器的元素结合到一个元组中.类似于zip(),只不过它返回一个迭代器而不是一个列表:
>>> zip([1, 2, 3], ['a', 'b', 'c'])
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> list(izip([1, 2, 3], ['a', 'b', 'c']))
[(1, 'a'), (2, 'b'), (3, 'c')]
islice()函数返回一个迭代器,它按索引返回由输入迭代器所选的元素.它和slice()函数功能类似,只是返回迭代器.
>>> from itertools import *
>>> count()
count(0)
>>> list(islice(count(), 5))
[0, 1, 2, 3, 4]
>>> list(islice(count(), 5, 10))
[5, 6, 7, 8, 9]
>>> list(islice(count(), 0, 100, 10))
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
tee()函数根据一个原输入迭代器返回多个独立的迭代器(默认为两个).
>>> from itertools import *
>>> r = islice(count(), 5)
>>> i1, i2 = tee(r)
>>> list(i1)
[0, 1, 2, 3, 4]
>>> list(i2)
[0, 1, 2, 3, 4]
tee()返回的迭代器可以用来为将并行处理的多个算法提供相同的数据集.但是tee()创建的新迭代器共享器输入迭代器,所以一旦创建了新迭代器,就不应再使用原迭代器.
from itertools import *
r = islice(count(), 5)
i1, i2 = tee(r)
print 'r:'
for i in r:
print i,
if i > 1:
break
print
print 'i1:', list(i1)
print 'i2:', list(i2)
print id(i1),id(i2),id(r)
解释器显示如下:
>>>
r:
0 1 2
i1: [3, 4]
i2: [3, 4]
42345288 42345160 43046456
2. 转换输入
imap()函数会返回一个迭代器,它对输入迭代器中的值调用一个函数并返回结果.imap()类似于map(),只不过只要有某个输入迭代器中的元素全部用完,imap()函数就会停止(而不是插入None值来完成利用所有输入).
from itertools import *
for i in imap(lambda x: 2 * x, range(5)):
print i,
print
for i in imap(lambda x, y: (x, y, x * y), range(5), range(5, 10)):
print '%d * %d = %d' % i
解释器显示如下:
>>>
0 2 4 6 8
0 * 5 = 0
1 * 6 = 6
2 * 7 = 14
3 * 8 = 24
4 * 9 = 36
starmap()函数类似于imap(),不过并不是由多个迭代器构建一个tuple,它使用*语法分解一个迭代器中的元素作为映射函数的参数:
from itertools import *
values = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]
for i in starmap(lambda x, y: (x, y, x * y), values):
print '%d * %d = %d' % i
解释器显示如下:
>>>
0 * 5 = 0
1 * 6 = 6
2 * 7 = 14
3 * 8 = 24
4 * 9 = 36
3. 生成新值
count()函数返回一个迭代器,能否无限的生成连续整数.第一个数可以作为参数传入(默认为0).这里没有上限参数:
from itertools import *
for i in izip(count(1), ['a', 'b', 'c']):
print i,
解释器显示如下:
>>>
(1, 'a') (2, 'b') (3, 'c')
而cycle()函数返回一个迭代器,它会无限的重复给定参数的内容.由于必须记住输入迭代器的全部内容,因此如果这个迭代器很长,可能会消费大量内存:
from itertools import *
for i, item in izip(range(7), cycle(['a', 'b', 'c'])):
print (i, item)
解释器显示如下:
>>>
(0, 'a')
(1, 'b')
(2, 'c')
(3, 'a')
(4, 'b')
(5, 'c')
(6, 'a')
而repeat()函数返回一个迭代器,每次访问时会生成相同的值:
>>> from itertools import *
>>> list(repeat('over-and-over', 5))
['over-and-over', 'over-and-over', 'over-and-over', 'over-and-over', 'over-and-over']
我们可以把repeat和imap等结合起来使用:
>>> list(imap(lambda x, y: (x, y, x * y), repeat(2), range(5)))
[(2, 0, 0), (2, 1, 2), (2, 2, 4), (2, 3, 6), (2, 4, 8)]
4. 过滤
dropwhile()函数返回一个迭代器,它会生成输入迭代器中条件第一次为false之后的元素:
from itertools import *
def should_drop(x):
print 'Testing:', x
return (x < 1)
for i in dropwhile(should_drop, [-1, 0, 1, 2, -2]):
print 'Yielding:', i
解释器显示如下:
>>>
Testing: -1
Testing: 0
Testing: 1
Yielding: 1
Yielding: 2
Yielding: -2
而takewhile()返回一个迭代器,这个迭代器将返回输入迭代器中保证测试条件为true的元素:
from itertools import *
def should_take(x):
print 'Testing:', x
return (x < 2)
for i in takewhile(should_take, [-1, 0, 1, 2, -2]):
print 'Yielding:', i
解释器显示如下:
>>>
Testing: -1
Yielding: -1
Testing: 0
Yielding: 0
Testing: 1
Yielding: 1
Testing: 2
ifilter和filter类似,但是返回的是迭代器:
>>> list(ifilter(lambda x: x < 1, [-1, 0, 1, 2, -2]))
[-1, 0, -2]
而ifilterfalse()顾名思义,返回为false的元素:
>>> list(ifilterfalse(lambda x: x < 1, [-1, 0, 1, 2, -2]))
[1, 2]
5. 数据分组
groupby()函数返回一个迭代器,它会生成一个按一个公共键组织的值集.
from itertools import *
import operator
import pprint
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return '(%s, %s)' % (self.x, self.y)
def __cmp__(self, other):
return cmp((self.x, self.y), (other.x, other.y))
data = list(imap(Point, cycle(islice(count(), 3)),
islice(count(), 7),))
print 'Data:'
pprint.pprint(data, width = 69)
print
print 'Grouped, unsorted:'
for k, g in groupby(data, operator.attrgetter('x')):
print k, list(g)
print
data.sort()
print 'Sorted:'
pprint.pprint(data, width = 69)
print
print 'Grouped, sorted:'
for k, g in groupby(data, operator.attrgetter('x')):
print k, list(g)
print
解释器显示如下:
>>>
Data:
[(0, 0), (1, 1), (2, 2), (0, 3), (1, 4), (2, 5), (0, 6)]
Grouped, unsorted:
0 [(0, 0)]
1 [(1, 1)]
2 [(2, 2)]
0 [(0, 3)]
1 [(1, 4)]
2 [(2, 5)]
0 [(0, 6)]
Sorted:
[(0, 0), (0, 3), (0, 6), (1, 1), (1, 4), (2, 2), (2, 5)]
Grouped, sorted:
0 [(0, 0), (0, 3), (0, 6)]
1 [(1, 1), (1, 4)]
2 [(2, 2), (2, 5)]
3. operator---内置操作符的函数接口
作用:内置操作符的函数接口
Python版本:1.4及以后版本
1. 逻辑操作
>>> a = -1
>>> b = 5
>>> from operator import *
>>> not_(a)
False
>>> truth(a)
True
>>> is_(a, b)
False
>>> is_not(a, b)
True
2. 比较操作符
>>> for func in (lt, le, eq, ne, ge, gt):
print '%s(a, b):' % func.__name__, func(a, b)
lt(a, b): True
le(a, b): True
eq(a, b): False
ne(a, b): True
ge(a, b): False
gt(a, b): False
3. 算术操作符
>>> a, b = -1, 5.0
>>> abs(a), neg(a)
(1, 1)
>>> add(a, b), div(a, b), floordiv(a, b), mod(a, b), pow(a, b), truediv(a, b)
(4.0, -0.2, -1.0, 4.0, -1.0, -0.2)
>>> c, d = 2, 6
>>> and_(c, d), invert(c), lshift(c, d), or_(c, d), rshift(d, c), xor(c, d)
(2, -3, 128, 6, 1, 4)
4. 序列操作符
处理序列的操作符可以划分为4组:建立序列,搜索元素,访问内容和从序列删除元素.
>>> a = [1, 2, 3]
>>> b = ['a', 'b', 'c']
>>> concat(a, b)
[1, 2, 3, 'a', 'b', 'c']
>>> repeat(a, 3)
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> contains(a, 1)
True
>>> countOf(a, 1)
1
>>> indexOf(a, 1)
0
>>> getitem(b, 1)
'b'
>>> getslice(a, 1, 3)
[2, 3]
>>> setitem(b, 1, 'd')
>>> b
['a', 'd', 'c']
>>> delitem(b, 1)
>>> b
['a', 'c']
5. 属性和元素"获取方法"
通过attrgetter()来直接获取元素参数的属性:
from operator import *
class MyObj(object):
def __init__(self, arg):
super(MyObj, self).__init__()
self.arg = arg
def __repr__(self):
return 'MyObj(%s)' % self.arg
lst = [MyObj(i) for i in range(5)]
print 'objects:', lst
g = attrgetter('arg')
vals = [g(i) for i in lst]
print 'arg values:', vals
lst.reverse()
print 'reversed :', lst
print 'sorted :', sorted(lst, key = g)
解释器显示如下:
>>>
objects: [MyObj(0), MyObj(1), MyObj(2), MyObj(3), MyObj(4)]
arg values: [0, 1, 2, 3, 4]
reversed : [MyObj(4), MyObj(3), MyObj(2), MyObj(1), MyObj(0)]
sorted : [MyObj(0), MyObj(1), MyObj(2), MyObj(3), MyObj(4)]
而我们可以通过itemgetter()来获取列表或字典的值:
from operator import *
lst = [dict(val = -1 * i) for i in range(4)]
print 'Dictionaries:', lst
g = itemgetter('val')
vals = [g(i) for i in lst]
print ' values:', vals
print ' sorted:', sorted(lst, key=g)
print
解释器显示如下:
>>>
Dictionaries: [{'val': 0}, {'val': -1}, {'val': -2}, {'val': -3}]
values: [0, -1, -2, -3]
sorted: [{'val': -3}, {'val': -2}, {'val': -1}, {'val': 0}]
6. 结合操作符和定制类
operator模块中的函数通过相应操作的标准Python接口完成工作,所以它们不仅适用于内置类型,还适用于用户定义的类:
from operator import *
class MyObj(object):
def __init__(self, val):
super(MyObj, self).__init__()
self.val = val
return
def __str__(self):
return 'MyObj(%s)' % self.val
def __lt__(self, other):
print 'Testing %s < %s' % (self, other)
return self.val < other.val
def __add__(self, other):
print 'Adding %s + %s' % (self, other)
return MyObj(self.val + other.val)
a = MyObj(1)
b = MyObj(2)
print lt(a, b)
print add(a, b)
解释器显示如下:
>>>
Testing MyObj(1) < MyObj(2)
True
Adding MyObj(1) + MyObj(2)
MyObj(3)
7. 类型检查
operator模块还包括一些函数来测试映射,数字和序列类型的API兼容性
from operator import *
class NoType(object):
pass
class MultiType(object):
def __len__(self):
return 0
def __getitem__(self, name):
return 'mapping'
def __init__(self):
pass
o = NoType()
t = MultiType()
for func in (isMappingType, isNumberType, isSequenceType):
print '%s(o):' % func.__name__, func(o)
print '%s(t):' % func.__name__, func(t)
解释器显示如下:
>>>
isMappingType(o): False
isMappingType(t): True
isNumberType(o): False
isNumberType(t): False
isSequenceType(o): False
isSequenceType(t): True
4. contextlib---上下文管理器工具
作用:创建和处理上下文管理器的工具
Python版本:2.5及以后版本
1. 上下文管理器API
上下文管理器要负责一个代码块中的资源,可能在进入代码块时创建资源,然后在退出代码块时清理这个资源.最常用的代码是读取文件内容:
>>> with open('test.txt') as fobj:
fobj.read()
'\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'
上下文管理器由with语句启用,这个API包含:__init__()初始化操作,__enter__()执行流进入with中时执行,__exit__()执行流离开with时执行:
class Context(object):
def __init__(self):
print '__init__()'
def __enter__(self):
print '__enter__()'
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print '__exit__()'
with Context():
print 'Doing work in the context'
解释器显示如下:
>>>
__init__()
__enter__()
Doing work in the context
__exit__()
如果在with语句的as子句中指定了名称,__enter__()方法可以返回与这个名称相关联的任何对象.
class WithinContext(object):
def __init__(self, context):
print 'withincontext.__init__(%s)' % context
def do_something(self):
print 'WithinContext.do_something()'
def __del__(self):
print 'WithinContext.__del__'
class Context(object):
def __init__(self):
print 'Context.__init__()'
def __enter__(self):
print 'Context.__enter__()'
return WithinContext(self)
def __exit__(self, exc_type, exc_val, exc_tb):
print 'Context.__exit__()'
with Context() as c:
c.do_something()
解释器显示如下:
>>>
Context.__init__()
Context.__enter__()
withincontext.__init__(<__main__.Context object at 0x00000000029A0978>)
WithinContext.do_something()
Context.__exit__()
而__exit__()方法接收一些参数,其中包含with块中产生的异常的详细信息:
class Context(object):
def __init__(self, handle_error):
print '__init__(%s)' % handle_error
self.handle_error = handle_error
def __enter__(self):
print '__enter__()'
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print '__exit__()'
print ' exc_type =', exc_type
print ' exc_val =', exc_val
print ' exc_tb =', exc_tb
return self.handle_error
with Context(True):
raise RuntimeError('error mesage handled')
print
with Context(False):
raise RuntimeError('error message propagated')
为True情况下,__exit__()可以处理这个异常.如果为False,则继续抛出此异常:
>>>
__init__(True)
__enter__()
__exit__()
exc_type = <type 'exceptions.RuntimeError'>
exc_val = error mesage handled
exc_tb = <traceback object at 0x0000000002752E88>
__init__(False)
__enter__()
__exit__()
exc_type = <type 'exceptions.RuntimeError'>
exc_val = error message propagated
exc_tb = <traceback object at 0x0000000002753208>
Traceback (most recent call last):
File "C:\Python27\test.py", line 21, in <module>
raise RuntimeError('error message propagated')
RuntimeError: error message propagated
2. 从生成器到上下文管理器
对于很少的上下文,完全没必要编写__enter__和__exit__方法.我们可以使用contextmanager()修饰符将一个生成器函数转换为上下文管理器.
import contextlib
@contextlib.contextmanager
def make_context():
print ' entering'
try:
yield()
except RuntimeError, err:
print ' ERROR:', err
finally:
print ' exiting'
print 'Normal:'
with make_context() as value:
print ' inside with statement:', value
print '\nhandled error:'
with make_context() as value:
raise RuntimeError('showing example of handling an error')
print '\nunhandled error:'
with make_context() as value:
raise ValueError('this exception is not handled')
解释器显示如下:
>>>
Normal:
entering
inside with statement: ()
exiting
handled error:
entering
ERROR: showing example of handling an error
exiting
unhandled error:
entering
exiting
Traceback (most recent call last):
File "C:\Python27\test.py", line 23, in <module>
raise ValueError('this exception is not handled')
ValueError: this exception is not handled
3. 嵌套上下文
import contextlib
@contextlib.contextmanager
def make_context(name):
print 'entering:', name
yield name
print 'exiting:', name
with make_context('A') as A, make_context('B') as B:
print 'inside with statement:', A, B
解释器显示如下:
>>>
entering: A
entering: B
inside with statement: A B
exiting: B
exiting: A
4. 关闭打开的句柄
并不是所有的对象都像file类一样自动关闭对象,所以我们需要使用closing为它创建一个上下文管理器:
import contextlib
class Door(object):
def __init__(self):
print '__init__()'
def close(self):
print 'close()'
print 'Normal Example:'
with contextlib.closing(Door()) as door:
print 'inside with statement'
print '\nError handling example:'
try:
with contextlib.closing(Door()) as door:
print ' raising from inside with statement'
raise RuntimeError('error message')
except Exception, err:
print ' Had an error:', err
无论是否存在错误,这个句柄都会关闭:
>>>
Normal Example:
__init__()
inside with statement
close()
Error handling example:
__init__()
raising from inside with statement
close()
Had an error: error message
转载于:https://my.oschina.net/voler/blog/382107