Ethan Furman added the comment: Your example shows /having/ an iterator, while mine is /being/ an iterator.
A simple iterator: # iterator protocol class uc_iter(): def __init__(self, text): self.text = text self.index = 0 def __iter__(self): return self def __next__(self): try: result = self.text[self.index].upper() except IndexError: raise StopIteration self.index += 1 return result ucii = uc_iter('abc') I believe your over-arching goal is a proxy class? class GenericProxy: def __init__(self, proxied): self.proxied = proxied # in case proxied is an __iter__ iterator @property def __iter__(self): if not hasattr(self.proxied, '__iter__'): raise AttributeError else: return self @property def __next__(self): if not hasattr(self.proxied, '__next__'): raise AttributeError else: return next(self.proxied) and then two proxies to test -- a non-iterable and an iterable: gp_ni = GenericProxy(object()) gp_ucii = GenericProxy(ucii) and a quick harness: try: for _ in iter(gp_ni): print(_) except Exception as e: print(e) try: for _ in iter(gp_ucii): print(_) except Exception as e: print(e) Note: the presence/absence of iter() makes no difference to the results below. The non-iterable gives the correct error: 'GenericProxy' object is not iterable But the iterable gives: 'GenericProxy' object is not callable That error message is a result of the iter machinery grabbing the __next__ attribute and trying to call it, but property attributes are not callable. In other words, iter() does not "honor the descriptor protocol". So now we have two: callable() and iter(). How many more are there? ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue23990> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com