diff --git a/python2/typing.py b/python2/typing.py index f6a73d706..6cd51c6b7 100644 --- a/python2/typing.py +++ b/python2/typing.py @@ -563,6 +563,29 @@ def __subclasscheck__(self, cls): AnyStr = TypeVar('AnyStr', bytes, unicode) +def _tp_cache(func): + maxsize = 128 + cache = {} + + @functools.wraps(func) + def inner(*args): + key = args + try: + return cache[key] + except TypeError: + # Assume it's an unhashable argument. + return func(*args) + except KeyError: + value = func(*args) + if len(cache) >= maxsize: + # If the cache grows too much, just start over. + cache.clear() + cache[key] = value + return value + + return inner + + class UnionMeta(TypingMeta): """Metaclass for Union.""" @@ -686,6 +709,7 @@ def __repr__(self): for t in self.__union_params__)) return r + @_tp_cache def __getitem__(self, parameters): if self.__union_params__ is not None: raise TypeError( @@ -731,6 +755,7 @@ class _Optional(_FinalTypingBase): __metaclass__ = OptionalMeta __slots__ = () + @_tp_cache def __getitem__(self, arg): arg = _type_check(arg, "Optional[t] requires a single type.") return Union[arg, type(None)] @@ -791,6 +816,7 @@ def __repr__(self): ', '.join(params)) return r + @_tp_cache def __getitem__(self, parameters): if self.__tuple_params__ is not None: raise TypeError("Cannot re-parameterize %r" % (self,)) @@ -1109,6 +1135,7 @@ def __eq__(self, other): def __hash__(self): return hash((self.__name__, self.__parameters__)) + @_tp_cache def __getitem__(self, params): if not isinstance(params, tuple): params = (params,)