@@ -117,14 +117,16 @@ class Dispatcher(object):
117117 >>> f(3.0)
118118 2.0
119119 """
120- __slots__ = '__name__' , 'name' , 'funcs' , '_ordering' , '_cache' , 'doc'
120+ __slots__ = '__name__' , 'name' , 'funcs' , '_ordering' , '_cache' , 'doc' , \
121+ '_lazy'
121122
122123 def __init__ (self , name , doc = None ):
123124 self .name = self .__name__ = name
124125 self .funcs = {}
125126 self .doc = doc
126127
127128 self ._cache = {}
129+ self ._lazy = False
128130
129131 def register (self , * types , ** kwargs ):
130132 """ register dispatcher with new implementation
@@ -214,9 +216,8 @@ def add(self, signature, func):
214216 return
215217
216218 new_signature = []
217-
218219 for index , typ in enumerate (signature , start = 1 ):
219- if not isinstance (typ , (type , list )):
220+ if not isinstance (typ , (type , list , str )):
220221 str_sig = ', ' .join (c .__name__ if isinstance (c , type )
221222 else str (c ) for c in signature )
222223 raise TypeError ("Tried to dispatch on non-type: %s\n "
@@ -237,9 +238,12 @@ def add(self, signature, func):
237238 'To use a variadic union type place the desired types '
238239 'inside of a tuple, e.g., [(int, str)]'
239240 )
240- new_signature .append (Variadic [typ [0 ]])
241- else :
242- new_signature .append (typ )
241+ typ = Variadic [typ [0 ]]
242+
243+ if isinstance (typ , str ):
244+ self ._lazy = True
245+
246+ new_signature .append (typ )
243247
244248 self .funcs [tuple (new_signature )] = func
245249 self ._cache .clear ()
@@ -264,6 +268,9 @@ def reorder(self, on_ambiguity=ambiguity_warn):
264268 return od
265269
266270 def __call__ (self , * args , ** kwargs ):
271+ if self ._lazy :
272+ self ._unlazy ()
273+
267274 types = tuple ([type (arg ) for arg in args ])
268275 try :
269276 func = self ._cache [types ]
@@ -359,6 +366,7 @@ def __setstate__(self, d):
359366 self .funcs = d ['funcs' ]
360367 self ._ordering = ordering (self .funcs )
361368 self ._cache = dict ()
369+ self ._lazy = any (isinstance (t , str ) for t in itl .chain (* d ['funcs' ]))
362370
363371 @property
364372 def __doc__ (self ):
@@ -400,6 +408,31 @@ def source(self, *args, **kwargs):
400408 """ Print source code for the function corresponding to inputs """
401409 print (self ._source (* args ))
402410
411+ def _unlazy (self ):
412+ funcs = {}
413+ for signature , func in self .funcs .items ():
414+ new_signature = []
415+ for typ in signature :
416+ if isinstance (typ , str ):
417+ for frame_info in inspect .stack ():
418+ frame = frame_info [0 ]
419+ scope = dict (frame .f_globals )
420+ scope .update (frame .f_locals )
421+ if typ in scope :
422+ typ = scope [typ ]
423+ break
424+ else :
425+ raise NameError ("name '%s' is not defined" % typ )
426+ new_signature .append (typ )
427+
428+ new_signature = tuple (new_signature )
429+ funcs [new_signature ] = func
430+
431+ self .funcs = funcs
432+ self .reorder ()
433+
434+ self ._lazy = False
435+
403436
404437def source (func ):
405438 s = 'File: %s\n \n ' % inspect .getsourcefile (func )
@@ -427,6 +460,9 @@ def __get__(self, instance, owner):
427460 return self
428461
429462 def __call__ (self , * args , ** kwargs ):
463+ if self ._lazy :
464+ self ._unlazy ()
465+
430466 types = tuple ([type (arg ) for arg in args ])
431467 func = self .dispatch (* types )
432468 if not func :
0 commit comments