In order to transition to python 3, I am trying to understand writing python 2 and python 3 compatible codes. The following code is from python-future.org
and illustrates a way to construct an iterator that would be compatible with both versions of python.
from builtins import object
class Upper(object):
def __init__(self, iterable):
self._iter = iter(iterable)
def __next__(self): # Py3-style iterator interface
return next(self._iter).upper() # builtin next() function calls
def __iter__(self):
return self
itr = Upper('hello')
assert next(itr) == 'H' # compatible style
assert list(itr) == list('ELLO')
The code runs fine in python 2, but to my surprise, if i remove the import statement then i get an error TypeError: Upper object is not an iterator
. I often derive my custom classes from object
but i have never imported it from builtins. Why does simply importing object
change the behaviour of the code?
The builtins module is automatically loaded every time Python interpreter starts, either as a top level execution environment or as interactive session. The Object class, which happens to be the base class for all Python objects, is defined in this module.
The import statement allows you to import one or more modules into your Python program, letting you make use of the definitions constructed in those modules.
__import__() . This means all semantics of the function are derived from importlib. __import__() . The most important difference between these two functions is that import_module() returns the specified package or module (e.g. pkg. mod ), while __import__() returns the top-level package or module (e.g. pkg ).
UPDATE You can find builtins module's code in Python/bltinmodule. c from the Python source code.
You are (indirectly) importing from the future.builtins
module; it provides a custom object
baseclass that adds forward-pointing special names.
In Python 2, iterators must have a next()
method (as well as __iter__
); this method was renamed to __next__
in Python 3. By not using the future.builtins.object
version you are simply missing the next
-> __next__
alias provided in Python 2.
See the source code for future.types.newobject.py
:
def next(self): if hasattr(self, '__next__'): return type(self).__next__(self) raise TypeError('newobject is not an iterator')
Note that builtins
will return standard built-in objects if you are running Python 3, the module only returns shims like these for Python 2.
You could simply add that same alias yourself:
class Upper(object):
def __init__(self, iterable):
self._iter = iter(iterable)
def __iter__(self):
return self
def __next__(self): # Py3-style iterator interface
return next(self._iter).upper() # builtin next() function calls
next = __next__ # Py2 alias
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With