# Buggy code
def _get_ufunc_and_otypes(self, func, args):
    """Return (ufunc, otypes)."""
    # frompyfunc will fail if args is empty
    assert args

    if self.otypes:
        otypes = self.otypes
        nout = len(otypes)

        # Note logic here: We only *use* self._ufunc if func is self.pyfunc
        # even though we set self._ufunc regardless.
        if func is self.pyfunc and self._ufunc is not None:
            ufunc = self._ufunc
        else:
            ufunc = self._ufunc = frompyfunc(func, len(args), nout)
    else:
        # Get number of outputs and output types by calling the function on
        # the first entries of args.  We also cache the result to prevent
        # the subsequent call when the ufunc is evaluated.
        # Assumes that ufunc first evaluates the 0th elements in the input
        # arrays (the input values are not checked to ensure this)
        inputs = [asarray(_a).flat[0] for _a in args]
        outputs = func(*inputs)

        # Performance note: profiling indicates that -- for simple
        # functions at least -- this wrapping can almost double the
        # execution time.
        # Hence we make it optional.
        if self.cache:
            _cache = [outputs]

            def _func(*vargs):
                if _cache:
                    return _cache.pop()
                else:
                    return func(*vargs)
        else:
            _func = func

        if isinstance(outputs, tuple):
            nout = len(outputs)
        else:
            nout = 1
            outputs = (outputs,)

        otypes = "".join([asarray(outputs[_k]).dtype.char for _k in range(nout)])

        # Performance note: profiling indicates that creating the ufunc is
        # not a significant cost compared with wrapping so it seems not
        # worth trying to cache this.
        ufunc = frompyfunc(_func, len(args), nout)

    return ufunc, otypes


# Traceback (AttributeError)
v = numpy.vectorize( lambda x: x )
v.otypes='i'
v( [1,2] )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/numpy/lib/function_base.py", line 1873, in __call__
return self._vectorize_call(func=func, args=vargs)
File "/usr/lib64/python2.7/site-packages/numpy/lib/function_base.py", line 1933, in _vectorize_call
ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)
File "/usr/lib64/python2.7/site-packages/numpy/lib/function_base.py", line 1886, in _get_ufunc_and_otypes
if func is self.pyfunc and self._ufunc is not None:
AttributeError: 'vectorize' object has no attribute '_ufunc'

# Fixed code
def _get_ufunc_and_otypes(self, func, args):
    """Return (ufunc, otypes)."""
    # frompyfunc will fail if args is empty
    if not args:
        raise ValueError("args can not be empty")

    if self.otypes:
        otypes = self.otypes
        nout = len(otypes)

        # Note logic here: We only *use* self._ufunc if func is self.pyfunc
        # even though we set self._ufunc regardless.
        if func is self.pyfunc and self._ufunc is not None:
            ufunc = self._ufunc
        else:
            ufunc = self._ufunc = frompyfunc(func, len(args), nout)
    else:
        # Get number of outputs and output types by calling the function on
        # the first entries of args.  We also cache the result to prevent
        # the subsequent call when the ufunc is evaluated.
        # Assumes that ufunc first evaluates the 0th elements in the input
        # arrays (the input values are not checked to ensure this)
        inputs = [asarray(_a).flat[0] for _a in args]
        outputs = func(*inputs)

        # Performance note: profiling indicates that -- for simple
        # functions at least -- this wrapping can almost double the
        # execution time.
        # Hence we make it optional.
        if self.cache:
            _cache = [outputs]

            def _func(*vargs):
                if _cache:
                    return _cache.pop()
                else:
                    return func(*vargs)
        else:
            _func = func

        if isinstance(outputs, tuple):
            nout = len(outputs)
        else:
            nout = 1
            outputs = (outputs,)

        otypes = "".join([asarray(outputs[_k]).dtype.char for _k in range(nout)])

        # Performance note: profiling indicates that creating the ufunc is
        # not a significant cost compared with wrapping so it seems not
        # worth trying to cache this.
        ufunc = frompyfunc(_func, len(args), nout)

    return ufunc, otypes