1919# import types, weakref # Deferred to single_dispatch()
2020from reprlib import recursive_repr
2121from _thread import RLock
22- from types import GenericAlias
2322
23+ # Avoid importing types, so we can speedup import time
24+ GenericAlias = type (list [int ])
2425
2526################################################################################
2627### update_wrapper() and wraps() decorator
@@ -236,14 +237,16 @@ def __ge__(self, other):
236237
237238def reduce (function , sequence , initial = _initial_missing ):
238239 """
239- reduce(function, iterable[, initial]) -> value
240-
241- Apply a function of two arguments cumulatively to the items of a sequence
242- or iterable, from left to right, so as to reduce the iterable to a single
243- value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
244- ((((1+2)+3)+4)+5). If initial is present, it is placed before the items
245- of the iterable in the calculation, and serves as a default when the
246- iterable is empty.
240+ reduce(function, iterable[, initial], /) -> value
241+
242+ Apply a function of two arguments cumulatively to the items of an iterable, from left to right.
243+
244+ This effectively reduces the iterable to a single value. If initial is present,
245+ it is placed before the items of the iterable in the calculation, and serves as
246+ a default when the iterable is empty.
247+
248+ For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
249+ calculates ((((1 + 2) + 3) + 4) + 5).
247250 """
248251
249252 it = iter (sequence )
@@ -284,7 +287,7 @@ def __new__(cls, func, /, *args, **keywords):
284287 if not callable (func ):
285288 raise TypeError ("the first argument must be callable" )
286289
287- if hasattr (func , "func" ):
290+ if isinstance (func , partial ):
288291 args = func .args + args
289292 keywords = {** func .keywords , ** keywords }
290293 func = func .func
@@ -302,13 +305,23 @@ def __call__(self, /, *args, **keywords):
302305
303306 @recursive_repr ()
304307 def __repr__ (self ):
305- qualname = type (self ).__qualname__
308+ cls = type (self )
309+ qualname = cls .__qualname__
310+ module = cls .__module__
306311 args = [repr (self .func )]
307312 args .extend (repr (x ) for x in self .args )
308313 args .extend (f"{ k } ={ v !r} " for (k , v ) in self .keywords .items ())
309- if type (self ).__module__ == "functools" :
310- return f"functools.{ qualname } ({ ', ' .join (args )} )"
311- return f"{ qualname } ({ ', ' .join (args )} )"
314+ return f"{ module } .{ qualname } ({ ', ' .join (args )} )"
315+
316+ def __get__ (self , obj , objtype = None ):
317+ if obj is None :
318+ return self
319+ import warnings
320+ warnings .warn ('functools.partial will be a method descriptor in '
321+ 'future Python versions; wrap it in staticmethod() '
322+ 'if you want to preserve the old behavior' ,
323+ FutureWarning , 2 )
324+ return self
312325
313326 def __reduce__ (self ):
314327 return type (self ), (self .func ,), (self .func , self .args ,
@@ -338,6 +351,9 @@ def __setstate__(self, state):
338351 self .args = args
339352 self .keywords = kwds
340353
354+ __class_getitem__ = classmethod (GenericAlias )
355+
356+
341357try :
342358 from _functools import partial
343359except ImportError :
@@ -372,28 +388,26 @@ def __init__(self, func, /, *args, **keywords):
372388 self .keywords = keywords
373389
374390 def __repr__ (self ):
375- args = ", " .join (map (repr , self .args ))
376- keywords = ", " .join ("{}={!r}" .format (k , v )
377- for k , v in self .keywords .items ())
378- format_string = "{module}.{cls}({func}, {args}, {keywords})"
379- return format_string .format (module = self .__class__ .__module__ ,
380- cls = self .__class__ .__qualname__ ,
381- func = self .func ,
382- args = args ,
383- keywords = keywords )
391+ cls = type (self )
392+ module = cls .__module__
393+ qualname = cls .__qualname__
394+ args = [repr (self .func )]
395+ args .extend (map (repr , self .args ))
396+ args .extend (f"{ k } ={ v !r} " for k , v in self .keywords .items ())
397+ return f"{ module } .{ qualname } ({ ', ' .join (args )} )"
384398
385399 def _make_unbound_method (self ):
386400 def _method (cls_or_self , / , * args , ** keywords ):
387401 keywords = {** self .keywords , ** keywords }
388402 return self .func (cls_or_self , * self .args , * args , ** keywords )
389403 _method .__isabstractmethod__ = self .__isabstractmethod__
390- _method ._partialmethod = self
404+ _method .__partialmethod__ = self
391405 return _method
392406
393407 def __get__ (self , obj , cls = None ):
394408 get = getattr (self .func , "__get__" , None )
395409 result = None
396- if get is not None :
410+ if get is not None and not isinstance ( self . func , partial ) :
397411 new_func = get (obj , cls )
398412 if new_func is not self .func :
399413 # Assume __get__ returning something new indicates the
@@ -423,6 +437,17 @@ def _unwrap_partial(func):
423437 func = func .func
424438 return func
425439
440+ def _unwrap_partialmethod (func ):
441+ prev = None
442+ while func is not prev :
443+ prev = func
444+ while isinstance (getattr (func , "__partialmethod__" , None ), partialmethod ):
445+ func = func .__partialmethod__
446+ while isinstance (func , partialmethod ):
447+ func = getattr (func , 'func' )
448+ func = _unwrap_partial (func )
449+ return func
450+
426451################################################################################
427452### LRU Cache function decorator
428453################################################################################
@@ -483,8 +508,9 @@ def lru_cache(maxsize=128, typed=False):
483508 can grow without bound.
484509
485510 If *typed* is True, arguments of different types will be cached separately.
486- For example, f(3.0) and f(3) will be treated as distinct calls with
487- distinct results.
511+ For example, f(decimal.Decimal("3.0")) and f(3.0) will be treated as
512+ distinct calls with distinct results. Some types such as str and int may
513+ be cached separately even when typed is false.
488514
489515 Arguments to the cached function must be hashable.
490516
@@ -660,7 +686,7 @@ def cache(user_function, /):
660686def _c3_merge (sequences ):
661687 """Merges MROs in *sequences* to a single MRO using the C3 algorithm.
662688
663- Adapted from https://www .python.org/download/releases/2.3/mro/ .
689+ Adapted from https://docs .python.org/3/howto/mro.html .
664690
665691 """
666692 result = []
@@ -905,7 +931,6 @@ def wrapper(*args, **kw):
905931 if not args :
906932 raise TypeError (f'{ funcname } requires at least '
907933 '1 positional argument' )
908-
909934 return dispatch (args [0 ].__class__ )(* args , ** kw )
910935
911936 funcname = getattr (func , '__name__' , 'singledispatch function' )
@@ -941,13 +966,18 @@ def register(self, cls, method=None):
941966 return self .dispatcher .register (cls , func = method )
942967
943968 def __get__ (self , obj , cls = None ):
969+ dispatch = self .dispatcher .dispatch
970+ funcname = getattr (self .func , '__name__' , 'singledispatchmethod method' )
944971 def _method (* args , ** kwargs ):
945- method = self .dispatcher .dispatch (args [0 ].__class__ )
946- return method .__get__ (obj , cls )(* args , ** kwargs )
972+ if not args :
973+ raise TypeError (f'{ funcname } requires at least '
974+ '1 positional argument' )
975+ return dispatch (args [0 ].__class__ ).__get__ (obj , cls )(* args , ** kwargs )
947976
948977 _method .__isabstractmethod__ = self .__isabstractmethod__
949978 _method .register = self .register
950979 update_wrapper (_method , self .func )
980+
951981 return _method
952982
953983 @property
@@ -966,6 +996,7 @@ def __init__(self, func):
966996 self .func = func
967997 self .attrname = None
968998 self .__doc__ = func .__doc__
999+ self .__module__ = func .__module__
9691000
9701001 def __set_name__ (self , owner , name ):
9711002 if self .attrname is None :
0 commit comments