'Memoized constructor for Terms.
Caching previously-constructed Terms is useful because it allows us to
only compute equivalent sub-expressions once when traversing a Pipeline
dependency graph.
Caching previously-constructed Terms is **sane** because terms and
their inputs are both conceptually immutable.'

def __new__(cls, domain=domain, dtype=dtype, missing_value=missing_value, window_safe=NotSpecified, ndim=NotSpecified, *args, **kwargs):

    if (domain is NotSpecified):
        domain = cls.domain
    if (dtype is NotSpecified):
        dtype = cls.dtype
    if (missing_value is NotSpecified):
        missing_value = cls.missing_value
    if (ndim is NotSpecified):
        ndim = cls.ndim
    if (window_safe is NotSpecified):
        window_safe = cls.window_safe
    (dtype, missing_value) = validate_dtype(cls.__name__, dtype, missing_value)
    params = cls._pop_params(kwargs)
    identity = cls._static_identity(domain=domain, dtype=dtype, missing_value=missing_value, window_safe=window_safe, ndim=ndim, params=params, *args, **kwargs)
    try:
        return cls._term_cache[identity]
    except KeyError:
        new_instance = cls._term_cache[identity] = super(Term, cls).__new__(cls)._init(domain=domain, dtype=dtype, missing_value=missing_value, window_safe=window_safe, ndim=ndim, params=params, *args, **kwargs)
        return new_instance
