Search code examples
pythonpython-3.xpython-itertoolspython-internals

In Python 3.x, why is there not an itertools shared-object on disk?


Is the itertools C module included somehow in the main Python binary in 3.x?

Assuming that the C module is built and included, which it appears to be:

>>> import inspect
>>> import itertools
>>>
>>> inspect.getsourcefile(itertools)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python3/3.4.3_2/Frameworks/Python.framework/Versions/3.4/lib/python3.4/inspect.py", line 571, in getsourcefile
    filename = getfile(object)
  File "/usr/local/Cellar/python3/3.4.3_2/Frameworks/Python.framework/Versions/3.4/lib/python3.4/inspect.py", line 518, in getfile
    raise TypeError('{!r} is a built-in module'.format(object))
TypeError: <module 'itertools' (built-in)> is a built-in module

I can't find an itertools.so for Python 3.x on my system, but there's one for 2.7.

I noted that some other C modules exist as shared objects (locate '.so' | grep -E '^/usr/local/' | grep '.so' e.g. mmap.so) on disk, so what's the deal with itertools? How can I use it if there's not a shared library?


Solution

  • There are hints in the makefile that's near the Python wrapper of inspect.py:

    /usr/local/Cellar/python3/3.4.3_2/Frameworks/Python.framework/Versions/3.4/lib/python3.4/config-3.4m/Makefile

    We can see the build rules for the itertools.c source:

    1668 Modules/itertoolsmodule.o: $(srcdir)/Modules/itertoolsmodule.c; $(CC) $(PY_CORE_CFLAGS)  -c $(srcdir)/Modules/itertoolsmodule.c -o      Modules/itertoolsmodule.o
    

    And then trace it a little to see that it's being bundled in:

     24 MODOBJS= ..  Modules/itertoolsmodule.o  ... Modules/xxsubtype.o
    
     462 # objects that get linked into the Python library
     463 LIBRARY_OBJS_OMIT_FROZEN=   \
    ...
     470         $(MODOBJS)
     471
     472 LIBRARY_OBJS=   \
     473         $(LIBRARY_OBJS_OMIT_FROZEN) \
     474         Python/frozen.o
     ...
     553 # Build the interpreter
     554 $(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
     555     $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Modules/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
     556
     557 platform: $(BUILDPYTHON) pybuilddir.txt
     558     $(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import sys ; from sysconfig import get_platform ; print(get_platform()+"-"+sys.version[0:     3])' >platform
     589 # Build static library
     ...
     598     $(AR) $(ARFLAGS) $@ $(MODOBJS)
     599     $(RANLIB) $@
    
     944 $(LIBRARY_OBJS) $(MODOBJS) Modules/python.o: $(PYTHON_HEADERS)
    

    Or if made via distutils, the path will be something like: /usr/local/Cellar/python3/3.4.3_2/Frameworks/Python.framework/Versions/3.4/lib/python3.4/_sysconfigdata.py

    And assuming that this gets built into a dynamic library:

    Ξ ~ → strings /usr/local/Cellar/python3/3.4.3_2/Frameworks/Python.framework/Versions/3.4/lib/libpython3.4.dylib | grep itertools
    itertools
    itertools._tee_dataobject
    itertools._tee
    itertools._grouper
    itertools.groupby
    itertools.repeat
    itertools.product
    ...
    

    Which means that at build time, the itertools.c module gets included in the libpython dynamic library, meaning that it's now part of the standard library.