functools32.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. """functools.py - Tools for working with functions and callable objects
  2. """
  3. # Python module wrapper for _functools C module
  4. # to allow utilities written in Python to be added
  5. # to the functools module.
  6. # Written by Nick Coghlan <ncoghlan at gmail.com>
  7. # and Raymond Hettinger <python at rcn.com>
  8. # Copyright (C) 2006-2010 Python Software Foundation.
  9. # See C source code for _functools credits/copyright
  10. __all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES',
  11. 'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial']
  12. from _functools import partial, reduce
  13. from collections import MutableMapping, namedtuple
  14. from .reprlib32 import recursive_repr as _recursive_repr
  15. from weakref import proxy as _proxy
  16. import sys as _sys
  17. try:
  18. from thread import allocate_lock as Lock
  19. except ImportError:
  20. from ._dummy_thread32 import allocate_lock as Lock
  21. ################################################################################
  22. ### OrderedDict
  23. ################################################################################
  24. class _Link(object):
  25. __slots__ = 'prev', 'next', 'key', '__weakref__'
  26. class OrderedDict(dict):
  27. 'Dictionary that remembers insertion order'
  28. # An inherited dict maps keys to values.
  29. # The inherited dict provides __getitem__, __len__, __contains__, and get.
  30. # The remaining methods are order-aware.
  31. # Big-O running times for all methods are the same as regular dictionaries.
  32. # The internal self.__map dict maps keys to links in a doubly linked list.
  33. # The circular doubly linked list starts and ends with a sentinel element.
  34. # The sentinel element never gets deleted (this simplifies the algorithm).
  35. # The sentinel is in self.__hardroot with a weakref proxy in self.__root.
  36. # The prev links are weakref proxies (to prevent circular references).
  37. # Individual links are kept alive by the hard reference in self.__map.
  38. # Those hard references disappear when a key is deleted from an OrderedDict.
  39. def __init__(self, *args, **kwds):
  40. '''Initialize an ordered dictionary. The signature is the same as
  41. regular dictionaries, but keyword arguments are not recommended because
  42. their insertion order is arbitrary.
  43. '''
  44. if len(args) > 1:
  45. raise TypeError('expected at most 1 arguments, got %d' % len(args))
  46. try:
  47. self.__root
  48. except AttributeError:
  49. self.__hardroot = _Link()
  50. self.__root = root = _proxy(self.__hardroot)
  51. root.prev = root.next = root
  52. self.__map = {}
  53. self.__update(*args, **kwds)
  54. def __setitem__(self, key, value,
  55. dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link):
  56. 'od.__setitem__(i, y) <==> od[i]=y'
  57. # Setting a new item creates a new link at the end of the linked list,
  58. # and the inherited dictionary is updated with the new key/value pair.
  59. if key not in self:
  60. self.__map[key] = link = Link()
  61. root = self.__root
  62. last = root.prev
  63. link.prev, link.next, link.key = last, root, key
  64. last.next = link
  65. root.prev = proxy(link)
  66. dict_setitem(self, key, value)
  67. def __delitem__(self, key, dict_delitem=dict.__delitem__):
  68. 'od.__delitem__(y) <==> del od[y]'
  69. # Deleting an existing item uses self.__map to find the link which gets
  70. # removed by updating the links in the predecessor and successor nodes.
  71. dict_delitem(self, key)
  72. link = self.__map.pop(key)
  73. link_prev = link.prev
  74. link_next = link.next
  75. link_prev.next = link_next
  76. link_next.prev = link_prev
  77. def __iter__(self):
  78. 'od.__iter__() <==> iter(od)'
  79. # Traverse the linked list in order.
  80. root = self.__root
  81. curr = root.next
  82. while curr is not root:
  83. yield curr.key
  84. curr = curr.next
  85. def __reversed__(self):
  86. 'od.__reversed__() <==> reversed(od)'
  87. # Traverse the linked list in reverse order.
  88. root = self.__root
  89. curr = root.prev
  90. while curr is not root:
  91. yield curr.key
  92. curr = curr.prev
  93. def clear(self):
  94. 'od.clear() -> None. Remove all items from od.'
  95. root = self.__root
  96. root.prev = root.next = root
  97. self.__map.clear()
  98. dict.clear(self)
  99. def popitem(self, last=True):
  100. '''od.popitem() -> (k, v), return and remove a (key, value) pair.
  101. Pairs are returned in LIFO order if last is true or FIFO order if false.
  102. '''
  103. if not self:
  104. raise KeyError('dictionary is empty')
  105. root = self.__root
  106. if last:
  107. link = root.prev
  108. link_prev = link.prev
  109. link_prev.next = root
  110. root.prev = link_prev
  111. else:
  112. link = root.next
  113. link_next = link.next
  114. root.next = link_next
  115. link_next.prev = root
  116. key = link.key
  117. del self.__map[key]
  118. value = dict.pop(self, key)
  119. return key, value
  120. def move_to_end(self, key, last=True):
  121. '''Move an existing element to the end (or beginning if last==False).
  122. Raises KeyError if the element does not exist.
  123. When last=True, acts like a fast version of self[key]=self.pop(key).
  124. '''
  125. link = self.__map[key]
  126. link_prev = link.prev
  127. link_next = link.next
  128. link_prev.next = link_next
  129. link_next.prev = link_prev
  130. root = self.__root
  131. if last:
  132. last = root.prev
  133. link.prev = last
  134. link.next = root
  135. last.next = root.prev = link
  136. else:
  137. first = root.next
  138. link.prev = root
  139. link.next = first
  140. root.next = first.prev = link
  141. def __sizeof__(self):
  142. sizeof = _sys.getsizeof
  143. n = len(self) + 1 # number of links including root
  144. size = sizeof(self.__dict__) # instance dictionary
  145. size += sizeof(self.__map) * 2 # internal dict and inherited dict
  146. size += sizeof(self.__hardroot) * n # link objects
  147. size += sizeof(self.__root) * n # proxy objects
  148. return size
  149. update = __update = MutableMapping.update
  150. keys = MutableMapping.keys
  151. values = MutableMapping.values
  152. items = MutableMapping.items
  153. __ne__ = MutableMapping.__ne__
  154. __marker = object()
  155. def pop(self, key, default=__marker):
  156. '''od.pop(k[,d]) -> v, remove specified key and return the corresponding
  157. value. If key is not found, d is returned if given, otherwise KeyError
  158. is raised.
  159. '''
  160. if key in self:
  161. result = self[key]
  162. del self[key]
  163. return result
  164. if default is self.__marker:
  165. raise KeyError(key)
  166. return default
  167. def setdefault(self, key, default=None):
  168. 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
  169. if key in self:
  170. return self[key]
  171. self[key] = default
  172. return default
  173. @_recursive_repr()
  174. def __repr__(self):
  175. 'od.__repr__() <==> repr(od)'
  176. if not self:
  177. return '%s()' % (self.__class__.__name__,)
  178. return '%s(%r)' % (self.__class__.__name__, list(self.items()))
  179. def __reduce__(self):
  180. 'Return state information for pickling'
  181. items = [[k, self[k]] for k in self]
  182. inst_dict = vars(self).copy()
  183. for k in vars(OrderedDict()):
  184. inst_dict.pop(k, None)
  185. if inst_dict:
  186. return (self.__class__, (items,), inst_dict)
  187. return self.__class__, (items,)
  188. def copy(self):
  189. 'od.copy() -> a shallow copy of od'
  190. return self.__class__(self)
  191. @classmethod
  192. def fromkeys(cls, iterable, value=None):
  193. '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
  194. If not specified, the value defaults to None.
  195. '''
  196. self = cls()
  197. for key in iterable:
  198. self[key] = value
  199. return self
  200. def __eq__(self, other):
  201. '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
  202. while comparison to a regular mapping is order-insensitive.
  203. '''
  204. if isinstance(other, OrderedDict):
  205. return len(self)==len(other) and \
  206. all(p==q for p, q in zip(self.items(), other.items()))
  207. return dict.__eq__(self, other)
  208. # update_wrapper() and wraps() are tools to help write
  209. # wrapper functions that can handle naive introspection
  210. WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
  211. WRAPPER_UPDATES = ('__dict__',)
  212. def update_wrapper(wrapper,
  213. wrapped,
  214. assigned = WRAPPER_ASSIGNMENTS,
  215. updated = WRAPPER_UPDATES):
  216. """Update a wrapper function to look like the wrapped function
  217. wrapper is the function to be updated
  218. wrapped is the original function
  219. assigned is a tuple naming the attributes assigned directly
  220. from the wrapped function to the wrapper function (defaults to
  221. functools.WRAPPER_ASSIGNMENTS)
  222. updated is a tuple naming the attributes of the wrapper that
  223. are updated with the corresponding attribute from the wrapped
  224. function (defaults to functools.WRAPPER_UPDATES)
  225. """
  226. wrapper.__wrapped__ = wrapped
  227. for attr in assigned:
  228. try:
  229. value = getattr(wrapped, attr)
  230. except AttributeError:
  231. pass
  232. else:
  233. setattr(wrapper, attr, value)
  234. for attr in updated:
  235. getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
  236. # Return the wrapper so this can be used as a decorator via partial()
  237. return wrapper
  238. def wraps(wrapped,
  239. assigned = WRAPPER_ASSIGNMENTS,
  240. updated = WRAPPER_UPDATES):
  241. """Decorator factory to apply update_wrapper() to a wrapper function
  242. Returns a decorator that invokes update_wrapper() with the decorated
  243. function as the wrapper argument and the arguments to wraps() as the
  244. remaining arguments. Default arguments are as for update_wrapper().
  245. This is a convenience function to simplify applying partial() to
  246. update_wrapper().
  247. """
  248. return partial(update_wrapper, wrapped=wrapped,
  249. assigned=assigned, updated=updated)
  250. def total_ordering(cls):
  251. """Class decorator that fills in missing ordering methods"""
  252. convert = {
  253. '__lt__': [('__gt__', lambda self, other: not (self < other or self == other)),
  254. ('__le__', lambda self, other: self < other or self == other),
  255. ('__ge__', lambda self, other: not self < other)],
  256. '__le__': [('__ge__', lambda self, other: not self <= other or self == other),
  257. ('__lt__', lambda self, other: self <= other and not self == other),
  258. ('__gt__', lambda self, other: not self <= other)],
  259. '__gt__': [('__lt__', lambda self, other: not (self > other or self == other)),
  260. ('__ge__', lambda self, other: self > other or self == other),
  261. ('__le__', lambda self, other: not self > other)],
  262. '__ge__': [('__le__', lambda self, other: (not self >= other) or self == other),
  263. ('__gt__', lambda self, other: self >= other and not self == other),
  264. ('__lt__', lambda self, other: not self >= other)]
  265. }
  266. roots = set(dir(cls)) & set(convert)
  267. if not roots:
  268. raise ValueError('must define at least one ordering operation: < > <= >=')
  269. root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__
  270. for opname, opfunc in convert[root]:
  271. if opname not in roots:
  272. opfunc.__name__ = opname
  273. opfunc.__doc__ = getattr(int, opname).__doc__
  274. setattr(cls, opname, opfunc)
  275. return cls
  276. def cmp_to_key(mycmp):
  277. """Convert a cmp= function into a key= function"""
  278. class K(object):
  279. __slots__ = ['obj']
  280. def __init__(self, obj):
  281. self.obj = obj
  282. def __lt__(self, other):
  283. return mycmp(self.obj, other.obj) < 0
  284. def __gt__(self, other):
  285. return mycmp(self.obj, other.obj) > 0
  286. def __eq__(self, other):
  287. return mycmp(self.obj, other.obj) == 0
  288. def __le__(self, other):
  289. return mycmp(self.obj, other.obj) <= 0
  290. def __ge__(self, other):
  291. return mycmp(self.obj, other.obj) >= 0
  292. def __ne__(self, other):
  293. return mycmp(self.obj, other.obj) != 0
  294. __hash__ = None
  295. return K
  296. _CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize")
  297. def lru_cache(maxsize=100):
  298. """Least-recently-used cache decorator.
  299. If *maxsize* is set to None, the LRU features are disabled and the cache
  300. can grow without bound.
  301. Arguments to the cached function must be hashable.
  302. View the cache statistics named tuple (hits, misses, maxsize, currsize) with
  303. f.cache_info(). Clear the cache and statistics with f.cache_clear().
  304. Access the underlying function with f.__wrapped__.
  305. See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
  306. """
  307. # Users should only access the lru_cache through its public API:
  308. # cache_info, cache_clear, and f.__wrapped__
  309. # The internals of the lru_cache are encapsulated for thread safety and
  310. # to allow the implementation to change (including a possible C version).
  311. def decorating_function(user_function,
  312. tuple=tuple, sorted=sorted, len=len, KeyError=KeyError):
  313. hits, misses = [0], [0]
  314. kwd_mark = (object(),) # separates positional and keyword args
  315. lock = Lock() # needed because OrderedDict isn't threadsafe
  316. if maxsize is None:
  317. cache = dict() # simple cache without ordering or size limit
  318. @wraps(user_function)
  319. def wrapper(*args, **kwds):
  320. key = args
  321. if kwds:
  322. key += kwd_mark + tuple(sorted(kwds.items()))
  323. try:
  324. result = cache[key]
  325. hits[0] += 1
  326. return result
  327. except KeyError:
  328. pass
  329. result = user_function(*args, **kwds)
  330. cache[key] = result
  331. misses[0] += 1
  332. return result
  333. else:
  334. cache = OrderedDict() # ordered least recent to most recent
  335. cache_popitem = cache.popitem
  336. cache_renew = cache.move_to_end
  337. @wraps(user_function)
  338. def wrapper(*args, **kwds):
  339. key = args
  340. if kwds:
  341. key += kwd_mark + tuple(sorted(kwds.items()))
  342. with lock:
  343. try:
  344. result = cache[key]
  345. cache_renew(key) # record recent use of this key
  346. hits[0] += 1
  347. return result
  348. except KeyError:
  349. pass
  350. result = user_function(*args, **kwds)
  351. with lock:
  352. cache[key] = result # record recent use of this key
  353. misses[0] += 1
  354. if len(cache) > maxsize:
  355. cache_popitem(0) # purge least recently used cache entry
  356. return result
  357. def cache_info():
  358. """Report cache statistics"""
  359. with lock:
  360. return _CacheInfo(hits[0], misses[0], maxsize, len(cache))
  361. def cache_clear():
  362. """Clear the cache and cache statistics"""
  363. with lock:
  364. cache.clear()
  365. hits[0] = misses[0] = 0
  366. wrapper.cache_info = cache_info
  367. wrapper.cache_clear = cache_clear
  368. return wrapper
  369. return decorating_function