---
# System prepended metadata

title: Inside the Python interpreter
tags: [python, rewrite]

---

Inside python interpreter
===
###### tags:`python`
:::info
Python 3.5
:::

# default builtins
sys.modules is a dictionary mapping the names of imported modules to the module object holding the code


```python
import sys
dir(sys.modules['builtins']) == dir(__builtins__)
```




    True




```python
sorted(sys.modules.keys())
```




    ['IPython',
     'IPython.core',
     'IPython.core.alias',
     'IPython.core.application',
     'IPython.core.autocall',
     'IPython.core.builtin_trap',
     'IPython.core.compilerop',
     'IPython.core.completer',
     'IPython.core.completerlib',
     'IPython.core.crashhandler',
     'IPython.core.debugger',
     'IPython.core.display',
     'IPython.core.display_trap',
     'IPython.core.displayhook',
     'IPython.core.displaypub',
     'IPython.core.error',
     'IPython.core.events',
     'IPython.core.excolors',
     'IPython.core.extensions',
     'IPython.core.formatters',
     'IPython.core.getipython',
     'IPython.core.history',
     'IPython.core.hooks',
     'IPython.core.inputsplitter',
     'IPython.core.inputtransformer',
     'IPython.core.interactiveshell',
     'IPython.core.latex_symbols',
     'IPython.core.logger',
     'IPython.core.macro',
     'IPython.core.magic',
     'IPython.core.magic_arguments',
     'IPython.core.magics',
     'IPython.core.magics.auto',
     'IPython.core.magics.basic',
     'IPython.core.magics.code',
     'IPython.core.magics.config',
     'IPython.core.magics.display',
     'IPython.core.magics.execution',
     'IPython.core.magics.extension',
     'IPython.core.magics.history',
     'IPython.core.magics.logging',
     'IPython.core.magics.namespace',
     'IPython.core.magics.osm',
     'IPython.core.magics.pylab',
     'IPython.core.magics.script',
     'IPython.core.oinspect',
     'IPython.core.page',
     'IPython.core.payload',
     'IPython.core.payloadpage',
     'IPython.core.prefilter',
     'IPython.core.profiledir',
     'IPython.core.pylabtools',
     'IPython.core.release',
     'IPython.core.shellapp',
     'IPython.core.splitinput',
     'IPython.core.ultratb',
     'IPython.core.usage',
     'IPython.display',
     'IPython.extensions',
     'IPython.extensions.storemagic',
     'IPython.lib',
     'IPython.lib.backgroundjobs',
     'IPython.lib.clipboard',
     'IPython.lib.display',
     'IPython.lib.pretty',
     'IPython.lib.security',
     'IPython.paths',
     'IPython.terminal',
     'IPython.terminal.debugger',
     'IPython.terminal.embed',
     'IPython.terminal.interactiveshell',
     'IPython.terminal.ipapp',
     'IPython.terminal.magics',
     'IPython.terminal.prompts',
     'IPython.terminal.pt_inputhooks',
     'IPython.terminal.ptutils',
     'IPython.terminal.shortcuts',
     'IPython.testing',
     'IPython.testing.skipdoctest',
     'IPython.utils',
     'IPython.utils.PyColorize',
     'IPython.utils._process_common',
     'IPython.utils._process_posix',
     'IPython.utils._sysinfo',
     'IPython.utils.capture',
     'IPython.utils.colorable',
     'IPython.utils.coloransi',
     'IPython.utils.contexts',
     'IPython.utils.data',
     'IPython.utils.decorators',
     'IPython.utils.dir2',
     'IPython.utils.encoding',
     'IPython.utils.frame',
     'IPython.utils.generics',
     'IPython.utils.importstring',
     'IPython.utils.io',
     'IPython.utils.ipstruct',
     'IPython.utils.module_paths',
     'IPython.utils.openpy',
     'IPython.utils.path',
     'IPython.utils.process',
     'IPython.utils.py3compat',
     'IPython.utils.sentinel',
     'IPython.utils.strdispatch',
     'IPython.utils.sysinfo',
     'IPython.utils.syspathcontext',
     'IPython.utils.tempdir',
     'IPython.utils.terminal',
     'IPython.utils.text',
     'IPython.utils.timing',
     'IPython.utils.tokenize2',
     'IPython.utils.tokenutil',
     'IPython.utils.wildcard',
     '__future__',
     '__main__',
     '__mp_main__',
     '_ast',
     '_bisect',
     '_bootlocale',
     '_bz2',
     '_codecs',
     '_collections',
     '_collections_abc',
     '_compat_pickle',
     '_compression',
     '_ctypes',
     '_curses',
     '_cython_0_25_1',
     '_datetime',
     '_decimal',
     '_frozen_importlib',
     '_frozen_importlib_external',
     '_functools',
     '_hashlib',
     '_heapq',
     '_imp',
     '_io',
     '_json',
     '_locale',
     '_lsprof',
     '_lzma',
     '_multiprocessing',
     '_opcode',
     '_operator',
     '_pickle',
     '_posixsubprocess',
     '_random',
     '_signal',
     '_sitebuiltins',
     '_socket',
     '_sqlite3',
     '_sre',
     '_stat',
     '_string',
     '_strptime',
     '_struct',
     '_sysconfigdata',
     '_sysconfigdata_m',
     '_thread',
     '_warnings',
     '_weakref',
     '_weakrefset',
     'abc',
     'apport_python_hook',
     'argparse',
     'array',
     'ast',
     'atexit',
     'base64',
     'bdb',
     'binascii',
     'bisect',
     'builtins',
     'bz2',
     'cProfile',
     'calendar',
     'cmd',
     'code',
     'codecs',
     'codeop',
     'collections',
     'collections.abc',
     'concurrent',
     'concurrent.futures',
     'concurrent.futures._base',
     'concurrent.futures.process',
     'concurrent.futures.thread',
     'contextlib',
     'copy',
     'copyreg',
     'ctypes',
     'ctypes._endian',
     'ctypes.util',
     'curses',
     'datetime',
     'dateutil',
     'dateutil._common',
     'dateutil.parser',
     'dateutil.relativedelta',
     'dateutil.tz',
     'dateutil.tz._common',
     'dateutil.tz.tz',
     'decimal',
     'decorator',
     'difflib',
     'dis',
     'email',
     'email._encoded_words',
     'email._parseaddr',
     'email._policybase',
     'email.base64mime',
     'email.charset',
     'email.encoders',
     'email.errors',
     'email.feedparser',
     'email.header',
     'email.iterators',
     'email.message',
     'email.parser',
     'email.quoprimime',
     'email.utils',
     'encodings',
     'encodings.aliases',
     'encodings.latin_1',
     'encodings.utf_8',
     'enum',
     'errno',
     'faulthandler',
     'fcntl',
     'fnmatch',
     'functools',
     'gc',
     'genericpath',
     'getopt',
     'getpass',
     'gettext',
     'glob',
     'grp',
     'hashlib',
     'heapq',
     'hmac',
     'html',
     'html.entities',
     'imp',
     'importlib',
     'importlib._bootstrap',
     'importlib._bootstrap_external',
     'importlib.abc',
     'importlib.machinery',
     'importlib.util',
     'inspect',
     'io',
     'ipykernel',
     'ipykernel._version',
     'ipykernel.codeutil',
     'ipykernel.comm',
     'ipykernel.comm.comm',
     'ipykernel.comm.manager',
     'ipykernel.connect',
     'ipykernel.datapub',
     'ipykernel.displayhook',
     'ipykernel.heartbeat',
     'ipykernel.iostream',
     'ipykernel.ipkernel',
     'ipykernel.jsonutil',
     'ipykernel.kernelapp',
     'ipykernel.kernelbase',
     'ipykernel.parentpoller',
     'ipykernel.pickleutil',
     'ipykernel.serialize',
     'ipykernel.zmqshell',
     'ipython_genutils',
     'ipython_genutils._version',
     'ipython_genutils.encoding',
     'ipython_genutils.importstring',
     'ipython_genutils.path',
     'ipython_genutils.py3compat',
     'ipython_genutils.text',
     'ipywidgets',
     'ipywidgets._version',
     'ipywidgets.widgets',
     'ipywidgets.widgets.domwidget',
     'ipywidgets.widgets.interaction',
     'ipywidgets.widgets.trait_types',
     'ipywidgets.widgets.valuewidget',
     'ipywidgets.widgets.widget',
     'ipywidgets.widgets.widget_bool',
     'ipywidgets.widgets.widget_box',
     'ipywidgets.widgets.widget_button',
     'ipywidgets.widgets.widget_color',
     'ipywidgets.widgets.widget_controller',
     'ipywidgets.widgets.widget_core',
     'ipywidgets.widgets.widget_date',
     'ipywidgets.widgets.widget_float',
     'ipywidgets.widgets.widget_image',
     'ipywidgets.widgets.widget_int',
     'ipywidgets.widgets.widget_layout',
     'ipywidgets.widgets.widget_link',
     'ipywidgets.widgets.widget_output',
     'ipywidgets.widgets.widget_selection',
     'ipywidgets.widgets.widget_selectioncontainer',
     'ipywidgets.widgets.widget_string',
     'ipywidgets.widgets.widget_style',
     'itertools',
     'jedi',
     'jedi._compatibility',
     'jedi.api',
     'jedi.api.classes',
     'jedi.api.completion',
     'jedi.api.helpers',
     'jedi.api.interpreter',
     'jedi.api.keywords',
     'jedi.api.usages',
     'jedi.cache',
     'jedi.common',
     'jedi.debug',
     'jedi.evaluate',
     'jedi.evaluate.analysis',
     'jedi.evaluate.cache',
     'jedi.evaluate.compiled',
     'jedi.evaluate.compiled.fake',
     'jedi.evaluate.compiled.mixed',
     'jedi.evaluate.context',
     'jedi.evaluate.docstrings',
     'jedi.evaluate.dynamic',
     'jedi.evaluate.filters',
     'jedi.evaluate.finder',
     'jedi.evaluate.flow_analysis',
     'jedi.evaluate.helpers',
     'jedi.evaluate.imports',
     'jedi.evaluate.instance',
     'jedi.evaluate.iterable',
     'jedi.evaluate.param',
     'jedi.evaluate.pep0484',
     'jedi.evaluate.precedence',
     'jedi.evaluate.recursion',
     'jedi.evaluate.representation',
     'jedi.evaluate.site',
     'jedi.evaluate.stdlib',
     'jedi.evaluate.sys_path',
     'jedi.parser',
     'jedi.parser.cache',
     'jedi.parser.parser',
     'jedi.parser.pgen2',
     'jedi.parser.pgen2.grammar',
     'jedi.parser.pgen2.parse',
     'jedi.parser.pgen2.pgen',
     'jedi.parser.python',
     'jedi.parser.python.diff',
     'jedi.parser.python.parser',
     'jedi.parser.python.tree',
     'jedi.parser.token',
     'jedi.parser.tokenize',
     'jedi.parser.tree',
     'jedi.settings',
     'json',
     'json.decoder',
     'json.encoder',
     'json.scanner',
     'jupyter_client',
     'jupyter_client._version',
     'jupyter_client.adapter',
     'jupyter_client.blocking',
     'jupyter_client.blocking.channels',
     'jupyter_client.blocking.client',
     'jupyter_client.channels',
     'jupyter_client.channelsabc',
     'jupyter_client.client',
     'jupyter_client.clientabc',
     'jupyter_client.connect',
     'jupyter_client.jsonutil',
     'jupyter_client.kernelspec',
     'jupyter_client.launcher',
     'jupyter_client.localinterfaces',
     'jupyter_client.manager',
     'jupyter_client.managerabc',
     'jupyter_client.multikernelmanager',
     'jupyter_client.session',
     'jupyter_core',
     'jupyter_core.paths',
     'jupyter_core.version',
     'keyrings',
     'keyword',
     'linecache',
     'locale',
     'logging',
     'logging.handlers',
     'lzma',
     'marshal',
     'math',
     'mimetypes',
     'multiprocessing',
     'multiprocessing.connection',
     'multiprocessing.context',
     'multiprocessing.process',
     'multiprocessing.reduction',
     'multiprocessing.util',
     'ntpath',
     'numbers',
     'opcode',
     'operator',
     'optparse',
     'os',
     'os.path',
     'pathlib',
     'pdb',
     'pexpect',
     'pexpect.exceptions',
     'pexpect.expect',
     'pexpect.pty_spawn',
     'pexpect.run',
     'pexpect.spawnbase',
     'pexpect.utils',
     'pickle',
     'pickleshare',
     'pkg_resources',
     'pkg_resources._vendor',
     'pkg_resources._vendor.packaging.__about__',
     'pkg_resources._vendor.six',
     'pkg_resources._vendor.six.moves',
     'pkg_resources.extern',
     'pkg_resources.extern.appdirs',
     'pkg_resources.extern.packaging',
     'pkg_resources.extern.packaging._compat',
     'pkg_resources.extern.packaging._structures',
     'pkg_resources.extern.packaging.markers',
     'pkg_resources.extern.packaging.requirements',
     'pkg_resources.extern.packaging.specifiers',
     'pkg_resources.extern.packaging.version',
     'pkg_resources.extern.pyparsing',
     'pkg_resources.extern.six',
     'pkg_resources.extern.six.moves',
     'pkg_resources.extern.six.moves.urllib',
     'pkgutil',
     'platform',
     'plistlib',
     'posix',
     'posixpath',
     'pprint',
     'profile',
     'prompt_toolkit',
     'prompt_toolkit.application',
     'prompt_toolkit.auto_suggest',
     'prompt_toolkit.buffer',
     'prompt_toolkit.buffer_mapping',
     'prompt_toolkit.cache',
     'prompt_toolkit.clipboard',
     'prompt_toolkit.clipboard.base',
     'prompt_toolkit.clipboard.in_memory',
     'prompt_toolkit.completion',
     'prompt_toolkit.document',
     'prompt_toolkit.enums',
     'prompt_toolkit.eventloop',
     'prompt_toolkit.eventloop.base',
     'prompt_toolkit.eventloop.callbacks',
     'prompt_toolkit.filters',
     'prompt_toolkit.filters.base',
     'prompt_toolkit.filters.cli',
     'prompt_toolkit.filters.types',
     'prompt_toolkit.filters.utils',
     'prompt_toolkit.history',
     'prompt_toolkit.input',
     'prompt_toolkit.interface',
     'prompt_toolkit.key_binding',
     'prompt_toolkit.key_binding.bindings',
     'prompt_toolkit.key_binding.bindings.basic',
     'prompt_toolkit.key_binding.bindings.completion',
     'prompt_toolkit.key_binding.bindings.emacs',
     'prompt_toolkit.key_binding.bindings.named_commands',
     'prompt_toolkit.key_binding.bindings.scroll',
     'prompt_toolkit.key_binding.bindings.vi',
     'prompt_toolkit.key_binding.defaults',
     'prompt_toolkit.key_binding.digraphs',
     'prompt_toolkit.key_binding.input_processor',
     'prompt_toolkit.key_binding.manager',
     'prompt_toolkit.key_binding.registry',
     'prompt_toolkit.key_binding.vi_state',
     'prompt_toolkit.keys',
     'prompt_toolkit.layout',
     'prompt_toolkit.layout.containers',
     'prompt_toolkit.layout.controls',
     'prompt_toolkit.layout.dimension',
     'prompt_toolkit.layout.lexers',
     'prompt_toolkit.layout.margins',
     'prompt_toolkit.layout.menus',
     'prompt_toolkit.layout.mouse_handlers',
     'prompt_toolkit.layout.processors',
     'prompt_toolkit.layout.prompt',
     'prompt_toolkit.layout.screen',
     'prompt_toolkit.layout.toolbars',
     'prompt_toolkit.layout.utils',
     'prompt_toolkit.mouse_events',
     'prompt_toolkit.output',
     'prompt_toolkit.reactive',
     'prompt_toolkit.renderer',
     'prompt_toolkit.search_state',
     'prompt_toolkit.selection',
     'prompt_toolkit.shortcuts',
     'prompt_toolkit.styles',
     'prompt_toolkit.styles.base',
     'prompt_toolkit.styles.defaults',
     'prompt_toolkit.styles.from_dict',
     'prompt_toolkit.styles.from_pygments',
     'prompt_toolkit.styles.utils',
     'prompt_toolkit.terminal',
     'prompt_toolkit.terminal.vt100_input',
     'prompt_toolkit.terminal.vt100_output',
     'prompt_toolkit.token',
     'prompt_toolkit.utils',
     'prompt_toolkit.validation',
     'pstats',
     'pty',
     'ptyprocess',
     'ptyprocess.ptyprocess',
     'ptyprocess.util',
     'pwd',
     'pydoc',
     'pydoc_data',
     'pydoc_data.topics',
     'pyexpat',
     'pyexpat.errors',
     'pyexpat.model',
     'pygments',
     'pygments.filter',
     'pygments.filters',
     'pygments.formatter',
     'pygments.formatters',
     'pygments.formatters._mapping',
     'pygments.formatters.html',
     'pygments.lexer',
     'pygments.lexers',
     'pygments.lexers._mapping',
     'pygments.lexers.python',
     'pygments.modeline',
     'pygments.plugin',
     'pygments.regexopt',
     'pygments.style',
     'pygments.styles',
     'pygments.styles.default',
     'pygments.token',
     'pygments.unistring',
     'pygments.util',
     'queue',
     'quopri',
     'random',
     're',
     'reprlib',
     'resource',
     'runpy',
     'select',
     'selectors',
     'shlex',
     'shutil',
     'signal',
     'simplegeneric',
     'simplejson',
     'simplejson._speedups',
     'simplejson.compat',
     'simplejson.decoder',
     'simplejson.encoder',
     'simplejson.scanner',
     'site',
     'sitecustomize',
     'six',
     'six.moves',
     'socket',
     'sqlite3',
     'sqlite3.dbapi2',
     'sre_compile',
     'sre_constants',
     'sre_parse',
     'stat',
     'storemagic',
     'string',
     'struct',
     'subprocess',
     'sys',
     'sysconfig',
     'tempfile',
     'termios',
     'textwrap',
     'threading',
     'time',
     'timeit',
     'token',
     'tokenize',
     'tornado',
     'tornado.concurrent',
     'tornado.escape',
     'tornado.ioloop',
     'tornado.log',
     'tornado.platform',
     'tornado.platform.auto',
     'tornado.platform.common',
     'tornado.platform.interface',
     'tornado.platform.posix',
     'tornado.speedups',
     'tornado.stack_context',
     'tornado.util',
     'traceback',
     'traitlets',
     'traitlets._version',
     'traitlets.config',
     'traitlets.config.application',
     'traitlets.config.configurable',
     'traitlets.config.loader',
     'traitlets.log',
     'traitlets.traitlets',
     'traitlets.utils',
     'traitlets.utils.bunch',
     'traitlets.utils.getargspec',
     'traitlets.utils.importstring',
     'traitlets.utils.sentinel',
     'tty',
     'types',
     'typing',
     'typing.io',
     'typing.re',
     'unicodedata',
     'urllib',
     'urllib.parse',
     'uu',
     'uuid',
     'warnings',
     'wcwidth',
     'wcwidth.table_wide',
     'wcwidth.table_zero',
     'wcwidth.wcwidth',
     'weakref',
     'xml',
     'xml.parsers',
     'xml.parsers.expat',
     'xml.parsers.expat.errors',
     'xml.parsers.expat.model',
     'zipfile',
     'zipimport',
     'zlib',
     'zmq',
     'zmq.backend',
     'zmq.backend.cython',
     'zmq.backend.cython._device',
     'zmq.backend.cython._poll',
     'zmq.backend.cython._version',
     'zmq.backend.cython.constants',
     'zmq.backend.cython.context',
     'zmq.backend.cython.error',
     'zmq.backend.cython.message',
     'zmq.backend.cython.socket',
     'zmq.backend.cython.utils',
     'zmq.backend.select',
     'zmq.error',
     'zmq.eventloop',
     'zmq.eventloop.ioloop',
     'zmq.eventloop.zmqstream',
     'zmq.sugar',
     'zmq.sugar.attrsettr',
     'zmq.sugar.constants',
     'zmq.sugar.context',
     'zmq.sugar.frame',
     'zmq.sugar.poll',
     'zmq.sugar.socket',
     'zmq.sugar.stopwatch',
     'zmq.sugar.tracker',
     'zmq.sugar.version',
     'zmq.utils',
     'zmq.utils.constant_names',
     'zmq.utils.jsonapi',
     'zmq.utils.strtypes']



## Built-in Modules


```python
for name in sys.builtin_module_names:
    print(name)
```

    _ast
    _bisect
    _codecs
    _collections
    _datetime
    _elementtree
    _functools
    _heapq
    _imp
    _io
    _locale
    _md5
    _operator
    _pickle
    _posixsubprocess
    _random
    _sha1
    _sha256
    _sha512
    _signal
    _socket
    _sre
    _stat
    _string
    _struct
    _symtable
    _thread
    _tracemalloc
    _warnings
    _weakref
    array
    atexit
    binascii
    builtins
    errno
    faulthandler
    fcntl
    gc
    grp
    itertools
    marshal
    math
    posix
    pwd
    pyexpat
    select
    spwd
    sys
    syslog
    time
    unicodedata
    xxsubtype
    zipimport
    zlib


## Import Path


```python
import sys

for d in sys.path:
    print(d)
```

    
    /usr/lib/python35.zip
    /usr/lib/python3.5
    /usr/lib/python3.5/plat-x86_64-linux-gnu
    /usr/lib/python3.5/lib-dynload
    /home/splasky/.local/lib/python3.5/site-packages
    /usr/local/lib/python3.5/dist-packages
    /usr/lib/python3/dist-packages
    /usr/local/lib/python3.5/dist-packages/IPython/extensions
    /home/splasky/.ipython



```python
%%writefile example.py
DATA='a'
```

    Writing example.py



```python
import example

print(example.__file__)
print(example.DATA)
```

    /home/splasky/jupyter-notebook/example.py
    a


> Changing the path between the initial import and the call to `reload()` means a different module may be loaded the second time.

# Import hook


```python
import sys

class NoisyImportFinder(object):
    
    PATH_TRIGGER = 'NoisyImportFinder_PATH_TRIGGER'
    
    def __init__(self, path_entry):
        print ('Checking NoisyImportFinder support for %s' % path_entry)
        if path_entry != self.PATH_TRIGGER:
            print ('NoisyImportFinder does not work for %s' % path_entry)
            raise ImportError()
        return
    
    def find_module(self, fullname, path=None):
        print ('NoisyImportFinder looking for "%s"' % fullname)
        return None

sys.path_hooks.append(NoisyImportFinder)

sys.path.insert(0, NoisyImportFinder.PATH_TRIGGER)

try:
    import target_module
except Exception as e:
    print ('Import failed:', e)
```

    Checking NoisyImportFinder support for NoisyImportFinder_PATH_TRIGGER
    NoisyImportFinder looking for "target_module"
    Import failed: No module named 'target_module'


# inside the main


```python
dir(sys.modules['__main__'])
```




    ['In', 'NamespaceMagics', 'NoisyImportFinder', 'Out', '_', '_10', '_7', '_Jupyter', '__', '___', '__builtin__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_dh', '_getsizeof', '_i', '_i1', '_i10', '_i11', '_i12', '_i13', '_i14', '_i15', '_i16', '_i17', '_i18', '_i19', '_i2', '_i20', '_i21', '_i22', '_i23', '_i24', '_i3', '_i4', '_i5', '_i6', '_i7', '_i8', '_i9', '_ih', '_ii', '_iii', '_nms', '_oh', 'd', 'dis', 'example', 'exit', 'get_ipython', 'getsizeof', 'json', 'name', 'oo', 'pprint', 'print_function', 'quit', 'sys', 'var_dic_list']




```python
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
```

# How python import work?


```python
import dis
```


```python
dis.dis("import sys")
```

      1           0 LOAD_CONST               0 (0)
                  3 LOAD_CONST               1 (None)
                  6 IMPORT_NAME              0 (sys)
                  9 STORE_NAME               0 (sys)
                 12 LOAD_CONST               1 (None)
                 15 RETURN_VALUE



```python
dis.dis("import os")
```

      1           0 LOAD_CONST               0 (0)
                  3 LOAD_CONST               1 (None)
                  6 IMPORT_NAME              0 (os)
                  9 STORE_NAME               0 (os)
                 12 LOAD_CONST               1 (None)
                 15 RETURN_VALUE



```python
# import module dynamically
sys = __import__('sys') 
print(sys)
```

    <module 'sys' (built-in)>



```python
oo = __import__('os') 
print(oo)
```

    <module 'os' from '/usr/lib/python3.5/os.py'>



```python
%%writefile c_modules.c
#include <Python.h>

static PyObject* helloworld(PyObject* self)
{
    return Py_BuildValue("s", "Hello, Python extensions!!");
}

static char helloworld_docs[] =
    "helloworld( ): Any message you want to put here!!\n";

static PyMethodDef helloworld_funcs[] = {
    {"helloworld", helloworld, 
     METH_NOARGS, helloworld_docs},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef helloworldModule = {
    PyModuleDef_HEAD_INIT,
    "hello",   /* name of module */
    helloworld_docs, /* module documentation, may be NULL */
    -1,       /* size of per-interpreter state of the module,
                 or -1 if the module keeps state in global variables. */
    helloworld_funcs
};


PyMODINIT_FUNC
PyInit_helloworld(void)
{
    return PyModule_Create(&helloworldModule);
}
```

    Overwriting c_modules.c



```python
%%writefile setup.py

from distutils.core import setup, Extension
setup(name='helloworld', version='1.0',  \
      ext_modules=[Extension('helloworld', ['c_modules.c'])])
```

    Overwriting setup.py


python3 ./setup.py install


## look inside how c module import into python

```python
# dis_import.py
import helloworld

helloworld.helloworld()
```
dis assembly the module
```
python -m dis dis_import.py

  6           0 LOAD_CONST               0 (0)
              2 LOAD_CONST               1 (None)
              4 IMPORT_NAME              0 (helloworld)
              6 STORE_NAME               0 (helloworld)

  8           8 LOAD_NAME                0 (helloworld)
             10 LOAD_METHOD              0 (helloworld)
             12 CALL_METHOD              0
             14 POP_TOP
             16 LOAD_CONST               1 (None)
             18 RETURN_VALUE
```

as same as like import python module

## take more look inside source code

IMPORT_NAME:
```c
 TARGET(IMPORT_NAME) {                                                                                                                                              
      ¦   ¦   PyObject *name = GETITEM(names, oparg);
      ¦   ¦   PyObject *fromlist = POP();
      ¦   ¦   PyObject *level = TOP();
      ¦   ¦   PyObject *res;
      ¦   ¦   res = import_name(f, name, fromlist, level);
      ¦   ¦   Py_DECREF(level);
      ¦   ¦   Py_DECREF(fromlist);
      ¦   ¦   SET_TOP(res);
      ¦   ¦   if (res == NULL)
      ¦   ¦   ¦   goto error;
      ¦   ¦   DISPATCH();
      ¦   }

...

static PyObject *
  import_name(PyFrameObject *f, PyObject *name, PyObject *fromlist, PyObject *level)
  {   
      _Py_IDENTIFIER(__import__);
      PyObject *import_func, *res;
      PyObject* stack[5];
      
      import_func = _PyDict_GetItemId(f->f_builtins, &PyId___import__);
      if (import_func == NULL) {
      ¦   PyErr_SetString(PyExc_ImportError, "__import__ not found");
      ¦   return NULL;
      }
      
      /* Fast path for not overloaded __import__. */
      if (import_func == PyThreadState_GET()->interp->import_func) {
      ¦   int ilevel = _PyLong_AsInt(level);
      ¦   if (ilevel == -1 && PyErr_Occurred()) {
      ¦   ¦   return NULL;
      ¦   }
      ¦   res = PyImport_ImportModuleLevelObject(
      ¦   ¦   ¦   ¦   ¦   name,
      ¦   ¦   ¦   ¦   ¦   f->f_globals,
      ¦   ¦   ¦   ¦   ¦   f->f_locals == NULL ? Py_None : f->f_locals,
      ¦   ¦   ¦   ¦   ¦   fromlist,
      ¦   ¦   ¦   ¦   ¦   ilevel);
      ¦   return res;
      }
  
      Py_INCREF(import_func);
      
      stack[0] = name;
      stack[1] = f->f_globals;
      stack[2] = f->f_locals == NULL ? Py_None : f->f_locals;
      stack[3] = fromlist;
      stack[4] = level;
      res = _PyObject_FastCall(import_func, stack, 5);
      Py_DECREF(import_func);
      return res;
}

PyObject *
  PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦PyObject *locals, PyObject *fromlist,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦int level)
  {
      _Py_IDENTIFIER(_find_and_load);
      _Py_IDENTIFIER(_handle_fromlist);
      PyObject *abs_name = NULL;
      PyObject *final_mod = NULL;
      PyObject *mod = NULL;
      PyObject *package = NULL;
      PyInterpreterState *interp = PyThreadState_GET()->interp;
      int has_from;
  
      if (name == NULL) {
      ¦   PyErr_SetString(PyExc_ValueError, "Empty module name");
      ¦   goto error;
      }
  
      /* The below code is importlib.__import__() & _gcd_import(), ported to C
      ¦  for added performance. */
  
      if (!PyUnicode_Check(name)) {
      ¦   PyErr_SetString(PyExc_TypeError, "module name must be a string");
      ¦   goto error;
      }
      if (PyUnicode_READY(name) < 0) {
      ¦   goto error;
      }
      if (level < 0) {
      ¦   PyErr_SetString(PyExc_ValueError, "level must be >= 0");
      ¦   goto error;
      }
  
      if (level > 0) {
      ¦   abs_name = resolve_name(name, globals, level);
      ¦   if (abs_name == NULL)
      ¦   ¦   goto error;
      }                        
      else {  /* level == 0 */
      ¦   if (PyUnicode_GET_LENGTH(name) == 0) {
      ¦   ¦   PyErr_SetString(PyExc_ValueError, "Empty module name");
      ¦   ¦   goto error;
      ¦   }
      ¦   abs_name = name;
      ¦   Py_INCREF(abs_name);
      }
  
      mod = PyImport_GetModule(abs_name);
      if (mod != NULL && mod != Py_None) {
      ¦   _Py_IDENTIFIER(__spec__);
      ¦   _Py_IDENTIFIER(_initializing);
      ¦   _Py_IDENTIFIER(_lock_unlock_module);
      ¦   PyObject *value = NULL;
      ¦   PyObject *spec;
      ¦   int initializing = 0;
  
      ¦   /* Optimization: only call _bootstrap._lock_unlock_module() if
      ¦   ¦  __spec__._initializing is true.
      ¦   ¦  NOTE: because of this, initializing must be set *before*
      ¦   ¦  stuffing the new module in sys.modules.
      ¦   ¦*/
      ¦   spec = _PyObject_GetAttrId(mod, &PyId___spec__);
      ¦   if (spec != NULL) {
      ¦   ¦   value = _PyObject_GetAttrId(spec, &PyId__initializing);
      ¦   ¦   Py_DECREF(spec);
      ¦   }
      ¦   if (value == NULL)
      ¦   ¦   PyErr_Clear();
      ¦   else {
      ¦   ¦   initializing = PyObject_IsTrue(value);
      ¦   ¦   Py_DECREF(value);
      ¦   ¦   if (initializing == -1)
      ¦   ¦   ¦   PyErr_Clear();
      ¦   ¦   if (initializing > 0) {
      ¦   ¦   ¦   value = _PyObject_CallMethodIdObjArgs(interp->importlib,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   &PyId__lock_unlock_module, abs_name,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   NULL);  
              ¦   if (value == NULL)
      ¦   ¦   ¦   ¦   goto error;
      ¦   ¦   ¦   Py_DECREF(value);
      ¦   ¦   }
      ¦   }
      }
      else {
      ¦   static int ximporttime = 0;
      ¦   static int import_level;
      ¦   static _PyTime_t accumulated;
      ¦   _Py_IDENTIFIER(importtime);
  
      ¦   _PyTime_t t1 = 0, accumulated_copy = accumulated;
  
      ¦   Py_XDECREF(mod);
  
      ¦   /* XOptions is initialized after first some imports.
      ¦   ¦* So we can't have negative cache.
      ¦   ¦* Anyway, importlib.__find_and_load is much slower than
      ¦   ¦* _PyDict_GetItemId()
      ¦   ¦*/
      ¦   if (ximporttime == 0) {
      ¦   ¦   PyObject *xoptions = PySys_GetXOptions();
      ¦   ¦   if (xoptions) {
      ¦   ¦   ¦   PyObject *value = _PyDict_GetItemId(xoptions, &PyId_importtime);
      ¦   ¦   ¦   ximporttime = (value == Py_True);
      ¦   ¦   }
      ¦   ¦   if (ximporttime) {
      ¦   ¦   ¦   fputs("import time: self [us] | cumulative | imported package\n",
      ¦   ¦   ¦   ¦   ¦ stderr);
      ¦   ¦   }
      ¦   }
  
      ¦   if (ximporttime) {
      ¦   ¦   import_level++;
      ¦   ¦   t1 = _PyTime_GetMonotonicClock();
      ¦   ¦   accumulated = 0;
      ¦   }
      ¦   if (PyDTrace_IMPORT_FIND_LOAD_START_ENABLED())
      ¦   ¦   PyDTrace_IMPORT_FIND_LOAD_START(PyUnicode_AsUTF8(abs_name));
  
      ¦   mod = _PyObject_CallMethodIdObjArgs(interp->importlib,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   &PyId__find_and_load, abs_name,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   interp->import_func, NULL);
  
      ¦   if (PyDTrace_IMPORT_FIND_LOAD_DONE_ENABLED())
      ¦   ¦   PyDTrace_IMPORT_FIND_LOAD_DONE(PyUnicode_AsUTF8(abs_name),
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦  mod != NULL);
  
      ¦   if (ximporttime) {
      ¦   ¦   _PyTime_t cum = _PyTime_GetMonotonicClock() - t1;
  
      ¦   ¦   import_level--;
      ¦   ¦   fprintf(stderr, "import time: %9ld | %10ld | %*s%s\n",
      ¦   ¦   ¦   ¦   (long)_PyTime_AsMicroseconds(cum - accumulated, _PyTime_ROUND_CEILING),
      ¦   ¦   ¦   ¦   (long)_PyTime_AsMicroseconds(cum, _PyTime_ROUND_CEILING),
      ¦   ¦   ¦   ¦   import_level*2, "", PyUnicode_AsUTF8(abs_name));
  
      ¦   ¦   accumulated = accumulated_copy + cum;
      ¦   }
  
      ¦   if (mod == NULL) {
      ¦   ¦   goto error;
      ¦   }
      }
  
      has_from = 0;
      if (fromlist != NULL && fromlist != Py_None) {
      ¦   has_from = PyObject_IsTrue(fromlist);
      ¦   if (has_from < 0)
      ¦   ¦   goto error;
      }
      if (!has_from) {
      ¦   Py_ssize_t len = PyUnicode_GET_LENGTH(name);
      ¦   if (level == 0 || len > 0) {
      ¦   ¦   Py_ssize_t dot;
          ¦   dot = PyUnicode_FindChar(name, '.', 0, len, 1);
      ¦   ¦   if (dot == -2) {
      ¦   ¦   ¦   goto error;
      ¦   ¦   }
  
      ¦   ¦   if (dot == -1) {
      ¦   ¦   ¦   /* No dot in module name, simple exit */
      ¦   ¦   ¦   final_mod = mod;
      ¦   ¦   ¦   Py_INCREF(mod);
      ¦   ¦   ¦   goto error;
      ¦   ¦   }
  
      ¦   ¦   if (level == 0) {
      ¦   ¦   ¦   PyObject *front = PyUnicode_Substring(name, 0, dot);
      ¦   ¦   ¦   if (front == NULL) {
      ¦   ¦   ¦   ¦   goto error;
      ¦   ¦   ¦   }
  
      ¦   ¦   ¦   final_mod = PyImport_ImportModuleLevelObject(front, NULL, NULL, NULL, 0);
      ¦   ¦   ¦   Py_DECREF(front);
      ¦   ¦   }
      ¦   ¦   else {
      ¦   ¦   ¦   Py_ssize_t cut_off = len - dot;
      ¦   ¦   ¦   Py_ssize_t abs_name_len = PyUnicode_GET_LENGTH(abs_name);
      ¦   ¦   ¦   PyObject *to_return = PyUnicode_Substring(abs_name, 0,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   abs_name_len - cut_off);
      ¦   ¦   ¦   if (to_return == NULL) {
      ¦   ¦   ¦   ¦   goto error;
      ¦   ¦   ¦   }
  
      ¦   ¦   ¦   final_mod = PyImport_GetModule(to_return);
      ¦   ¦   ¦   Py_DECREF(to_return);
      ¦   ¦   ¦   if (final_mod == NULL) {
      ¦   ¦   ¦   ¦       ¦   ¦   ¦   ¦   PyErr_Format(PyExc_KeyError,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦"%R not in sys.modules as expected",
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦to_return);
      ¦   ¦   ¦   ¦   goto error;
      ¦   ¦   ¦   }
      ¦   ¦   }
      ¦   }
      ¦   else {
      ¦   ¦   final_mod = mod;
      ¦   ¦   Py_INCREF(mod);
      ¦   }
      }
      else {
      ¦   final_mod = _PyObject_CallMethodIdObjArgs(interp->importlib,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦ &PyId__handle_fromlist, mod,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦ fromlist, interp->import_func,
      ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦   ¦ NULL);
      }
  
    error:
      Py_XDECREF(abs_name);
      Py_XDECREF(mod);
      Py_XDECREF(package);
      if (final_mod == NULL)
      ¦   remove_importlib_frames();
      return final_mod;
  }
```

```c
/* --- Core PyObject call functions ------------------------------- */
  
  PyObject *
  _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
      ¦   ¦   ¦   ¦   ¦  PyObject *kwargs)
  {
      /* _PyObject_FastCallDict() must not be called with an exception set,
      ¦  because it can clear it (directly or indirectly) and so the
      ¦  caller loses its exception */
      assert(!PyErr_Occurred());
  
      assert(callable != NULL);
      assert(nargs >= 0);
      assert(nargs == 0 || args != NULL);
      assert(kwargs == NULL || PyDict_Check(kwargs));
  
      if (PyFunction_Check(callable)) {
      ¦   return _PyFunction_FastCallDict(callable, args, nargs, kwargs);
      }
      else if (PyCFunction_Check(callable)) {
      ¦   return _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
      }
      else {
      ¦   PyObject *argstuple, *result;
      ¦   ternaryfunc call;
  
      ¦   /* Slow-path: build a temporary tuple */
      ¦   call = callable->ob_type->tp_call;
      ¦   if (call == NULL) {
      ¦   ¦   PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
      ¦   ¦   ¦   ¦   ¦   ¦callable->ob_type->tp_name);
      ¦   ¦   return NULL;
      ¦   }
  
      ¦   argstuple = _PyStack_AsTuple(args, nargs);
      ¦   if (argstuple == NULL) {
      ¦   ¦   return NULL;
      ¦   }

      ¦   if (Py_EnterRecursiveCall(" while calling a Python object")) {
      ¦   ¦   Py_DECREF(argstuple);
      ¦   ¦   return NULL;
      ¦   }
  
      ¦   result = (*call)(callable, argstuple, kwargs);
  
      ¦   Py_LeaveRecursiveCall();
      ¦   Py_DECREF(argstuple);
  
      ¦   result = _Py_CheckFunctionResult(callable, result, NULL);
      ¦   return result;
      }
  }
  

```
                                                   

# compile and eval


```python
compile?
```

```
Signature: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
Docstring:
Compile source into a code object that can be executed by exec() or eval().

The source code may represent a Python module, statement or expression.
The filename will be used for run-time error messages.
The mode must be 'exec' to compile a module, 'single' to compile a
single (interactive) statement, or 'eval' to compile an expression.
The flags argument, if present, controls which future statements influence
the compilation of the code.
The dont_inherit argument, if true, stops the compilation inheriting
the effects of any future statements in effect in the code calling
compile; if absent or false these statements do influence the compilation,
in addition to any features explicitly specified.
Type:      builtin_function_or_method
```
    

# bytecode
Python source code is compiled into bytecode, the internal representation of a Python program in the CPython interpreter. The bytecode is also cached in .pyc files so that executing the same file is faster the second time (recompilation from source to bytecode can be avoided). This “intermediate language” is said to run on a virtual machine that executes the machine code corresponding to each bytecode. Do note that bytecodes are not expected to work between different Python virtual machines, nor to be stable between Python releases.

> A list of bytecode instructions can be found in the documentation for the dis module.



```python
help(exec)
```

    Help on built-in function exec in module builtins:
    
    exec(source, globals=None, locals=None, /)
        Execute the given source in the context of globals and locals.
        
        The source may be a string representing one or more Python statements
        or a code object as returned by compile().
        The globals must be a dictionary and locals can be any mapping,
        defaulting to the current globals and locals.
        If only globals is given, locals defaults to it.
    



```python
help(eval)
```

    Help on built-in function eval in module builtins:
    
    eval(source, globals=None, locals=None, /)
        Evaluate the given source in the context of globals and locals.
        
        The source may be a string representing a Python expression
        or a code object as returned by compile().
        The globals must be a dictionary and locals can be any mapping,
        defaulting to the current globals and locals.
        If only globals is given, locals defaults to it.
    


所以`eval`執行的內容必須是`expression`,而`exec`是都可以執行,但是回傳值固定為None。


```python
code_str="""
def hello():
    print("hello world")
hello()
"""
```


```python
exec('print(5)')           # prints 5.
# exec 'print 5'     if you use Python 2.x, nor the exec neither the print is a function there
exec('print(5)\nprint(6)')  # prints 5{newline}6.
exec('if True: print(6)')  # prints 6.
exec('5')  
```

    5
    5
    6
    6



```python
eval('5')              # x <- 5
eval('%d + 6' % x)     # x <- 11
eval('abs(%d)' % -100) # x <- 100
eval('x = 5')          # INVALID; assignment is not an expression.
eval('if 1: x = 4')    # INVALID; if is a statement, not an expression.
```


    ---------------------------------------------------------------------------

    TypeError                                 Traceback (most recent call last)

    <ipython-input-107-40888bad4179> in <module>()
          1 eval('5')              # x <- 5
    ----> 2 eval('%d + 6' % x)     # x <- 11
          3 eval('abs(%d)' % -100) # x <- 100
          4 eval('x = 5')          # INVALID; assignment is not an expression.
          5 eval('if 1: x = 4')    # INVALID; if is a statement, not an expression.


    TypeError: %d format: a number is required, not generator



```python
code_obj_exec=compile(code_str,'string','exec')
code_obj_exec
exec(code_obj_exec)
```

    hello world



```python
eval(compile('42', '<string>', 'exec'))  # code return None
```


```python
eval(compile('42', '<string>', 'eval'))  # code returns 42
```




    42




```python
exec(compile('42', '<string>', 'eval'))  # code returns 42,but ignored by exec
```


```python
code_obj_signle=compile(code_str,'string','single')
exec(code_obj_signle)
```


    Traceback (most recent call last):


      File "/usr/local/lib/python3.5/dist-packages/IPython/core/interactiveshell.py", line 2862, in run_code
        exec(code_obj, self.user_global_ns, self.user_ns)


      File "<ipython-input-112-e920440df200>", line 1, in <module>
        code_obj_signle=compile(code_str,'string','single')


      File "string", line 4
        hello()
            ^
    SyntaxError: invalid syntax



而single 只接受oneline statment


```python
code_obj_eval=compile(code_str,'string','eval')
```


    Traceback (most recent call last):


      File "/usr/local/lib/python3.5/dist-packages/IPython/core/interactiveshell.py", line 2862, in run_code
        exec(code_obj, self.user_global_ns, self.user_ns)


      File "<ipython-input-113-686a1487d9cc>", line 1, in <module>
        code_obj_eval=compile(code_str,'string','eval')


      File "string", line 2
        def hello():
          ^
    SyntaxError: invalid syntax




```python
exec('print("hello")')
```

    hello



```python
eval("print('hello')")
```

    hello



```python
exec("3+5")
```


```python
eval("3+5")
```




    8



Actually the statement "<span class="girk">eval accepts only a single expression</span>" applies only when a string (which contains Python source code) is passed to eval. Then it is internally compiled to bytecode using compile(source, '<string>', 'eval') This is where the difference really comes from.

If a code object (which contains Python bytecode) is passed to exec or eval, <span class="mark">they behave identically</span>, excepting for the fact that exec ignores the return value, still returning None always. So it is possible use eval to execute something that has statements, if you just compiled it into bytecode before instead of passing it as a string:


```python
eval(compile('if 1: print("Hello")', '<string>', 'exec'))
```

    Hello


It should work.

## The longer answer, a.k.a the gory details

* The `exec` function (which was a statement in Python 2) is used for executing a dynamically created statement or program.
* The `eval` function does the same for a single expression, and returns the value of the expression.

exec and eval both accept the program/expression to be run either as a str, unicode or bytes object containing source code, or as a code object which contains Python bytecode.

If a str/unicode/bytes containing source code was passed to exec, it behaves equivalently to:
```
exec(compile(source, '<string>', 'exec'))
```
and eval similarly behaves equivalent to:
```
eval(compile(source, '<string>', 'eval'))
```


```python
def my_func(arg):
    print("Called with %d" % arg)
    return arg * 2
```


```python
exec('my_func(42)')
```

    Called with 42



```python
eval('my_func(42)')
```

    Called with 42





    84



# 深入code object

## Code objects
Code objects represent byte-compiled executable Python code, or bytecode.
The difference between a code object and a function object is that the function object contains an explicit reference to the function’s globals (the module in which it was defined), while a code object contains no context; also the default argument values are stored in the function object, not in the code object (because they represent values calculated at run-time). Unlike function objects, code objects are immutable and contain no references (directly or indirectly) to mutable objects.

```
code	
    co_argcount	number of arguments (not including keyword only arguments, * or ** args)
 	co_code	string of raw compiled bytecode
 	co_cellvars	tuple of names of cell variables (referenced by containing scopes)
 	co_consts	tuple of constants used in the bytecode
 	co_filename	name of file in which this code object was created
 	co_firstlineno	number of first line in Python source code
 	co_flags	bitmap of CO_* flags, read more here
 	co_lnotab	encoded mapping of line numbers to bytecode indices
 	co_freevars	tuple of names of free variables (referenced via a function’s closure)
 	co_kwonlyargcount	number of keyword only arguments (not including ** arg)
 	co_name	name with which this code object was defined
 	co_names	tuple of names of local variables
 	co_nlocals	number of local variables
 	co_stacksize	virtual machine stack space required
 	co_varnames	tuple of names of arguments and local variables
```
可以參考python的[inspect lib](https://docs.python.org/3/library/inspect.html)

## code object implement
inside `include/code.h`
```c
/* Bytecode object */
typedef struct {
    PyObject_HEAD int co_argcount; /* #arguments, except *args */
    int co_kwonlyargcount;         /* #keyword only arguments */
    int co_nlocals;                /* #local variables */
    int co_stacksize;              /* #entries needed for evaluation stack */
    int co_flags;                  /* CO_..., see below */
    int co_firstlineno;            /* first source line number */
    PyObject* co_code;             /* instruction opcodes */
    PyObject* co_consts;           /* list (constants used) */
    PyObject* co_names;            /* list of strings (names used) */
    PyObject* co_varnames;         /* tuple of strings (local variable names) */
    PyObject* co_freevars;         /* tuple of strings (free variable names) */
    PyObject* co_cellvars;         /* tuple of strings (cell variable names) */
    /* The rest aren't used in either hash or comparisons, except for co_name,
       used in both. This is done to preserve the name and line number
       for tracebacks and debuggers; otherwise, constant de-duplication
       would collapse identical functions/lambdas defined on different lines.
    */
    Py_ssize_t* co_cell2arg;  /* Maps cell vars which are arguments. */
    PyObject* co_filename;    /* unicode (where it was loaded from) */
    PyObject* co_name;        /* unicode (name, for reference) */
    PyObject* co_lnotab;      /* string (encoding addr<->lineno mapping) See
                                 Objects/lnotab_notes.txt for details. */
    void* co_zombieframe;     /* for optimization only (see frameobject.c) */
    PyObject* co_weakreflist; /* to support weakrefs to code objects */
    /* Scratch space for extra data relating to the code object.
       Type is a void* to keep the format private in codeobject.c to force
       people to go through the proper APIs. */
    void* co_extra;
} PyCodeObject;
```

## more about code object

### inside the code object


```python
code_obj=compile(code_str,'string','exec')
dir(code_obj)
```




    ['__class__',
     '__delattr__',
     '__dir__',
     '__doc__',
     '__eq__',
     '__format__',
     '__ge__',
     '__getattribute__',
     '__gt__',
     '__hash__',
     '__init__',
     '__le__',
     '__lt__',
     '__ne__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     'co_argcount',
     'co_cellvars',
     'co_code',
     'co_consts',
     'co_filename',
     'co_firstlineno',
     'co_flags',
     'co_freevars',
     'co_kwonlyargcount',
     'co_lnotab',
     'co_name',
     'co_names',
     'co_nlocals',
     'co_stacksize',
     'co_varnames']



### get code object code


```python
code_obj.co_code
```




    b'd\x00\x00d\x01\x00\x84\x00\x00Z\x00\x00e\x00\x00\x83\x00\x00\x01d\x02\x00S'




```python
[x for x in code_obj.co_code]
```




    [100,
     0,
     0,
     100,
     1,
     0,
     132,
     0,
     0,
     90,
     0,
     0,
     101,
     0,
     0,
     131,
     0,
     0,
     1,
     100,
     2,
     0,
     83]




```python
dis.show_code(code_obj)
```

    Name:              <module>
    Filename:          string
    Argument count:    0
    Kw-only arguments: 0
    Number of locals:  0
    Stack size:        2
    Flags:             NOFREE
    Constants:
       0: <code object hello at 0x7f01fc67f030, file "string", line 2>
       1: 'hello'
       2: None
    Names:
       0: hello



```python
dis.dis(code_obj)
```

      2           0 LOAD_CONST               0 (<code object hello at 0x7f01fc67f030, file "string", line 2>)
                  3 LOAD_CONST               1 ('hello')
                  6 MAKE_FUNCTION            0
                  9 STORE_NAME               0 (hello)
    
      4          12 LOAD_NAME                0 (hello)
                 15 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
                 18 POP_TOP
                 19 LOAD_CONST               2 (None)
                 22 RETURN_VALUE


和上面的code object做對照


```python
iterator=dis.get_instructions(code_str)
for it in iterator:
    print(it.opcode)
```

    100
    100
    132
    90
    101
    131
    1
    100
    83



```python
op=code_obj.co_code[0]
op
```




    100




```python
opcode.opname[op]
```




    'LOAD_CONST'



可以發現opcode是python的一個module，他負責定義python interpreter會用到的instruction，所以我們才可以透過dis來disassembly python bytecode,而code object是bytecode的表現形式。

python中opcode的value和python virtual machine所定義的instruction相同(定義於opcode.h中，和dis.opmap的value互相對應)，因此可以透過實做interpreter(不管任何形式)產生的python bytecode來讓python virtual machine執行。


```python
code_obj.co_consts
```




    (<code object hello at 0x7f3768227d20, file "string", line 2>, 'hello', None)




```python
code_obj.co_lnotab
```




    b'\x0c\x03'




```python
code_obj.co_freevars
```




    ()




```python
code_obj.co_stacksize
```




    3



# A Detour into Code Disassembly


```python
import dis
def hello():
    print("Hello world")
```


```python
code_str="""
def print_hello(x,y):
    print("hello")
    return x+y
hello(10,11)
"""
```


```python
code_obj=compile(code_str,'string','exec')
dis.dis(code_obj)
```

      2           0 LOAD_CONST               0 (<code object print_hello at 0x7f01fc6fde40, file "string", line 2>)
                  3 LOAD_CONST               1 ('print_hello')
                  6 MAKE_FUNCTION            0
                  9 STORE_NAME               0 (print_hello)
    
      5          12 LOAD_NAME                1 (hello)
                 15 LOAD_CONST               2 (10)
                 18 LOAD_CONST               3 (11)
                 21 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
                 24 POP_TOP
                 25 LOAD_CONST               4 (None)
                 28 RETURN_VALUE


|line number|bytecode offect|bytecode|bytecode argument|
|:---------:|:-------------:|:------:|:---------------:|
|5|12|LOAD_NAME|0(hello)


```python
bytecode=dis.Bytecode(hello)
bytecode
```




    Bytecode(<function hello at 0x7f01fc74fd90>)




```python
help(bytecode)
```

    Help on Bytecode in module dis object:
    
    class Bytecode(builtins.object)
     |  The bytecode operations of a piece of code
     |  
     |  Instantiate this with a function, method, string of code, or a code object
     |  (as returned by compile()).
     |  
     |  Iterating over this yields the bytecode operations as Instruction instances.
     |  
     |  Methods defined here:
     |  
     |  __init__(self, x, *, first_line=None, current_offset=None)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |  
     |  __iter__(self)
     |  
     |  __repr__(self)
     |      Return repr(self).
     |  
     |  dis(self)
     |      Return a formatted view of the bytecode operations.
     |  
     |  info(self)
     |      Return formatted information about the code object.
     |  
     |  ----------------------------------------------------------------------
     |  Class methods defined here:
     |  
     |  from_traceback(tb) from builtins.type
     |      Construct a Bytecode from the given traceback
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  __dict__
     |      dictionary for instance variables (if defined)
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
    



```python
bytecode.dis()
```




    "  3           0 LOAD_GLOBAL              0 (print)\n              3 LOAD_CONST               1 ('Hello world')\n              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)\n              9 POP_TOP\n             10 LOAD_CONST               0 (None)\n             13 RETURN_VALUE\n"




```python
bytecode.info()
```




    "Name:              hello\nFilename:          <ipython-input-70-9b74c1c13393>\nArgument count:    0\nKw-only arguments: 0\nNumber of locals:  0\nStack size:        2\nFlags:             OPTIMIZED, NEWLOCALS, NOFREE\nConstants:\n   0: None\n   1: 'Hello world'\nNames:\n   0: print"




```python
for instr in bytecode:
    print(instr.opname)

```

    LOAD_GLOBAL
    LOAD_CONST
    CALL_FUNCTION
    POP_TOP
    LOAD_CONST
    RETURN_VALUE



```python
dis.dis(hello)
```

      3           0 LOAD_GLOBAL              0 (print)
                  3 LOAD_CONST               1 ('Hello world')
                  6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                  9 POP_TOP
                 10 LOAD_CONST               0 (None)
                 13 RETURN_VALUE



```python
import opcode
help(opcode)
```

    Help on module opcode:
    
    NAME
        opcode
    
    MODULE REFERENCE
        https://docs.python.org/3.5/library/opcode
        
        The following documentation is automatically generated from the Python
        source files.  It may be incomplete, incorrect or include features that
        are considered implementation detail and may vary between Python
        implementations.  When in doubt, consult the module reference at the
        location listed above.
    
    DESCRIPTION
        opcode module - potentially shared between dis and other modules which
        operate on bytecodes (e.g. peephole optimizers).
    
    FUNCTIONS
        stack_effect(opcode, oparg=None, /)
            Compute the stack effect of the opcode.
    
    DATA
        EXTENDED_ARG = 144
        HAVE_ARGUMENT = 90
        __all__ = ['cmp_op', 'hasconst', 'hasname', 'hasjrel', 'hasjabs', 'has...
        cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is', 'is ...
        hascompare = [107]
        hasconst = [100]
        hasfree = [135, 136, 137, 138, 148]
        hasjabs = [111, 112, 113, 114, 115, 119]
        hasjrel = [93, 110, 120, 121, 122, 143, 154]
        haslocal = [124, 125, 126]
        hasname = [90, 91, 95, 96, 97, 98, 101, 106, 108, 109, 116]
        hasnargs = [131, 140, 141, 142]
        opmap = {'BEFORE_ASYNC_WITH': 52, 'BINARY_ADD': 23, 'BINARY_AND': 64, ...
        opname = ['<0>', 'POP_TOP', 'ROT_TWO', 'ROT_THREE', 'DUP_TOP', 'DUP_TO...
    
    FILE
        /usr/lib/python3.5/opcode.py
    
    



```python
dis.code_info(hello)
```




    "Name:              hello\nFilename:          <ipython-input-70-9b74c1c13393>\nArgument count:    0\nKw-only arguments: 0\nNumber of locals:  0\nStack size:        2\nFlags:             OPTIMIZED, NEWLOCALS, NOFREE\nConstants:\n   0: None\n   1: 'Hello world'\nNames:\n   0: print"




```python
dis.show_code(hello)
```

    Name:              hello
    Filename:          <ipython-input-70-9b74c1c13393>
    Argument count:    0
    Kw-only arguments: 0
    Number of locals:  0
    Stack size:        2
    Flags:             OPTIMIZED, NEWLOCALS, NOFREE
    Constants:
       0: None
       1: 'Hello world'
    Names:
       0: print



```python
help(dis.distb)
```

    Help on function distb in module dis:
    
    distb(tb=None, *, file=None)
        Disassemble a traceback (default: last traceback).
    



```python
dis.disassemble(code_obj)
```

      2           0 LOAD_CONST               0 (<code object print_hello at 0x7f01fc6fde40, file "string", line 2>)
                  3 LOAD_CONST               1 ('print_hello')
                  6 MAKE_FUNCTION            0
                  9 STORE_NAME               0 (print_hello)
    
      5          12 LOAD_NAME                1 (hello)
                 15 LOAD_CONST               2 (10)
                 18 LOAD_CONST               3 (11)
                 21 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
                 24 POP_TOP
                 25 LOAD_CONST               4 (None)
                 28 RETURN_VALUE



```python
dis.disco(code_obj)
```

      2           0 LOAD_CONST               0 (<code object print_hello at 0x7f01fc6fde40, file "string", line 2>)
                  3 LOAD_CONST               1 ('print_hello')
                  6 MAKE_FUNCTION            0
                  9 STORE_NAME               0 (print_hello)
    
      5          12 LOAD_NAME                1 (hello)
                 15 LOAD_CONST               2 (10)
                 18 LOAD_CONST               3 (11)
                 21 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
                 24 POP_TOP
                 25 LOAD_CONST               4 (None)
                 28 RETURN_VALUE


這兩個function的作用是一樣的


```python
iterator=dis.get_instructions(code_str)
for it in iterator:
    print(it)
```

    Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=<code object print_hello at 0x7f01fc6f5030, file "<disassembly>", line 2>, argrepr='<code object print_hello at 0x7f01fc6f5030, file "<disassembly>", line 2>', offset=0, starts_line=2, is_jump_target=False)
    Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval='print_hello', argrepr="'print_hello'", offset=3, starts_line=None, is_jump_target=False)
    Instruction(opname='MAKE_FUNCTION', opcode=132, arg=0, argval=0, argrepr='', offset=6, starts_line=None, is_jump_target=False)
    Instruction(opname='STORE_NAME', opcode=90, arg=0, argval='print_hello', argrepr='print_hello', offset=9, starts_line=None, is_jump_target=False)
    Instruction(opname='LOAD_NAME', opcode=101, arg=1, argval='hello', argrepr='hello', offset=12, starts_line=5, is_jump_target=False)
    Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=10, argrepr='10', offset=15, starts_line=None, is_jump_target=False)
    Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=11, argrepr='11', offset=18, starts_line=None, is_jump_target=False)
    Instruction(opname='CALL_FUNCTION', opcode=131, arg=2, argval=2, argrepr='2 positional, 0 keyword pair', offset=21, starts_line=None, is_jump_target=False)
    Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=24, starts_line=None, is_jump_target=False)
    Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval=None, argrepr='None', offset=25, starts_line=None, is_jump_target=False)
    Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False)


```
opname - human readable name for operation
opcode - numeric code for operation
arg - numeric argument to operation (if any), otherwise None
argval - resolved arg value (if known), otherwise same as arg
argrepr - human readable description of operation argument
offset - start index of operation within bytecode sequence
starts_line - line started by this opcode (if any), otherwise None
is_jump_target - True if other code jumps to here, otherwise False 
```


```python
x=dis.findlinestarts(code_obj)
next(x)
```




    (0, 2)




```python
next(x)
```




    (12, 5)




```python
help(dis.stack_effect)
```

    Help on built-in function stack_effect in module _opcode:
    
    stack_effect(opcode, oparg=None, /)
        Compute the stack effect of the opcode.
    



```python
dis.stack_effect(1) # POP_TOP
```




    -1




```python
help(dis.findlabels)
```

    Help on function findlabels in module dis:
    
    findlabels(code)
        Detect all offsets in a byte code which are jump targets.
        
        Return the list of offsets.
    



```python
def f(x):
    if x == 0:
        return 1
    elif x==1:
        return 2
```


```python
dis.disco(f.__code__)
```

      2           0 LOAD_FAST                0 (x)
                  3 LOAD_CONST               1 (0)
                  6 COMPARE_OP               2 (==)
                  9 POP_JUMP_IF_FALSE       16
    
      3          12 LOAD_CONST               2 (1)
                 15 RETURN_VALUE
    
      4     >>   16 LOAD_FAST                0 (x)
                 19 LOAD_CONST               2 (1)
                 22 COMPARE_OP               2 (==)
                 25 POP_JUMP_IF_FALSE       32
    
      5          28 LOAD_CONST               3 (2)
                 31 RETURN_VALUE
            >>   32 LOAD_CONST               0 (None)
                 35 RETURN_VALUE



```python
dis.findlabels(f.__code__.co_code)
```




    [16, 32]




```python
dis.opname
```




    ['<0>',
     'POP_TOP',
     'ROT_TWO',
     'ROT_THREE',
     'DUP_TOP',
     'DUP_TOP_TWO',
     '<6>',
     '<7>',
     '<8>',
     'NOP',
     'UNARY_POSITIVE',
     'UNARY_NEGATIVE',
     'UNARY_NOT',
     '<13>',
     '<14>',
     'UNARY_INVERT',
     'BINARY_MATRIX_MULTIPLY',
     'INPLACE_MATRIX_MULTIPLY',
     '<18>',
     'BINARY_POWER',
     'BINARY_MULTIPLY',
     '<21>',
     'BINARY_MODULO',
     'BINARY_ADD',
     'BINARY_SUBTRACT',
     'BINARY_SUBSCR',
     'BINARY_FLOOR_DIVIDE',
     'BINARY_TRUE_DIVIDE',
     'INPLACE_FLOOR_DIVIDE',
     'INPLACE_TRUE_DIVIDE',
     '<30>',
     '<31>',
     '<32>',
     '<33>',
     '<34>',
     '<35>',
     '<36>',
     '<37>',
     '<38>',
     '<39>',
     '<40>',
     '<41>',
     '<42>',
     '<43>',
     '<44>',
     '<45>',
     '<46>',
     '<47>',
     '<48>',
     '<49>',
     'GET_AITER',
     'GET_ANEXT',
     'BEFORE_ASYNC_WITH',
     '<53>',
     '<54>',
     'INPLACE_ADD',
     'INPLACE_SUBTRACT',
     'INPLACE_MULTIPLY',
     '<58>',
     'INPLACE_MODULO',
     'STORE_SUBSCR',
     'DELETE_SUBSCR',
     'BINARY_LSHIFT',
     'BINARY_RSHIFT',
     'BINARY_AND',
     'BINARY_XOR',
     'BINARY_OR',
     'INPLACE_POWER',
     'GET_ITER',
     'GET_YIELD_FROM_ITER',
     'PRINT_EXPR',
     'LOAD_BUILD_CLASS',
     'YIELD_FROM',
     'GET_AWAITABLE',
     '<74>',
     'INPLACE_LSHIFT',
     'INPLACE_RSHIFT',
     'INPLACE_AND',
     'INPLACE_XOR',
     'INPLACE_OR',
     'BREAK_LOOP',
     'WITH_CLEANUP_START',
     'WITH_CLEANUP_FINISH',
     'RETURN_VALUE',
     'IMPORT_STAR',
     '<85>',
     'YIELD_VALUE',
     'POP_BLOCK',
     'END_FINALLY',
     'POP_EXCEPT',
     'STORE_NAME',
     'DELETE_NAME',
     'UNPACK_SEQUENCE',
     'FOR_ITER',
     'UNPACK_EX',
     'STORE_ATTR',
     'DELETE_ATTR',
     'STORE_GLOBAL',
     'DELETE_GLOBAL',
     '<99>',
     'LOAD_CONST',
     'LOAD_NAME',
     'BUILD_TUPLE',
     'BUILD_LIST',
     'BUILD_SET',
     'BUILD_MAP',
     'LOAD_ATTR',
     'COMPARE_OP',
     'IMPORT_NAME',
     'IMPORT_FROM',
     'JUMP_FORWARD',
     'JUMP_IF_FALSE_OR_POP',
     'JUMP_IF_TRUE_OR_POP',
     'JUMP_ABSOLUTE',
     'POP_JUMP_IF_FALSE',
     'POP_JUMP_IF_TRUE',
     'LOAD_GLOBAL',
     '<117>',
     '<118>',
     'CONTINUE_LOOP',
     'SETUP_LOOP',
     'SETUP_EXCEPT',
     'SETUP_FINALLY',
     '<123>',
     'LOAD_FAST',
     'STORE_FAST',
     'DELETE_FAST',
     '<127>',
     '<128>',
     '<129>',
     'RAISE_VARARGS',
     'CALL_FUNCTION',
     'MAKE_FUNCTION',
     'BUILD_SLICE',
     'MAKE_CLOSURE',
     'LOAD_CLOSURE',
     'LOAD_DEREF',
     'STORE_DEREF',
     'DELETE_DEREF',
     '<139>',
     'CALL_FUNCTION_VAR',
     'CALL_FUNCTION_KW',
     'CALL_FUNCTION_VAR_KW',
     'SETUP_WITH',
     'EXTENDED_ARG',
     'LIST_APPEND',
     'SET_ADD',
     'MAP_ADD',
     'LOAD_CLASSDEREF',
     'BUILD_LIST_UNPACK',
     'BUILD_MAP_UNPACK',
     'BUILD_MAP_UNPACK_WITH_CALL',
     'BUILD_TUPLE_UNPACK',
     'BUILD_SET_UNPACK',
     'SETUP_ASYNC_WITH',
     '<155>',
     '<156>',
     '<157>',
     '<158>',
     '<159>',
     '<160>',
     '<161>',
     '<162>',
     '<163>',
     '<164>',
     '<165>',
     '<166>',
     '<167>',
     '<168>',
     '<169>',
     '<170>',
     '<171>',
     '<172>',
     '<173>',
     '<174>',
     '<175>',
     '<176>',
     '<177>',
     '<178>',
     '<179>',
     '<180>',
     '<181>',
     '<182>',
     '<183>',
     '<184>',
     '<185>',
     '<186>',
     '<187>',
     '<188>',
     '<189>',
     '<190>',
     '<191>',
     '<192>',
     '<193>',
     '<194>',
     '<195>',
     '<196>',
     '<197>',
     '<198>',
     '<199>',
     '<200>',
     '<201>',
     '<202>',
     '<203>',
     '<204>',
     '<205>',
     '<206>',
     '<207>',
     '<208>',
     '<209>',
     '<210>',
     '<211>',
     '<212>',
     '<213>',
     '<214>',
     '<215>',
     '<216>',
     '<217>',
     '<218>',
     '<219>',
     '<220>',
     '<221>',
     '<222>',
     '<223>',
     '<224>',
     '<225>',
     '<226>',
     '<227>',
     '<228>',
     '<229>',
     '<230>',
     '<231>',
     '<232>',
     '<233>',
     '<234>',
     '<235>',
     '<236>',
     '<237>',
     '<238>',
     '<239>',
     '<240>',
     '<241>',
     '<242>',
     '<243>',
     '<244>',
     '<245>',
     '<246>',
     '<247>',
     '<248>',
     '<249>',
     '<250>',
     '<251>',
     '<252>',
     '<253>',
     '<254>',
     '<255>']




```python
sorted(dis.opmap.items(),key=lambda x:x[1])
```




    [('POP_TOP', 1),
     ('ROT_TWO', 2),
     ('ROT_THREE', 3),
     ('DUP_TOP', 4),
     ('DUP_TOP_TWO', 5),
     ('NOP', 9),
     ('UNARY_POSITIVE', 10),
     ('UNARY_NEGATIVE', 11),
     ('UNARY_NOT', 12),
     ('UNARY_INVERT', 15),
     ('BINARY_MATRIX_MULTIPLY', 16),
     ('INPLACE_MATRIX_MULTIPLY', 17),
     ('BINARY_POWER', 19),
     ('BINARY_MULTIPLY', 20),
     ('BINARY_MODULO', 22),
     ('BINARY_ADD', 23),
     ('BINARY_SUBTRACT', 24),
     ('BINARY_SUBSCR', 25),
     ('BINARY_FLOOR_DIVIDE', 26),
     ('BINARY_TRUE_DIVIDE', 27),
     ('INPLACE_FLOOR_DIVIDE', 28),
     ('INPLACE_TRUE_DIVIDE', 29),
     ('GET_AITER', 50),
     ('GET_ANEXT', 51),
     ('BEFORE_ASYNC_WITH', 52),
     ('INPLACE_ADD', 55),
     ('INPLACE_SUBTRACT', 56),
     ('INPLACE_MULTIPLY', 57),
     ('INPLACE_MODULO', 59),
     ('STORE_SUBSCR', 60),
     ('DELETE_SUBSCR', 61),
     ('BINARY_LSHIFT', 62),
     ('BINARY_RSHIFT', 63),
     ('BINARY_AND', 64),
     ('BINARY_XOR', 65),
     ('BINARY_OR', 66),
     ('INPLACE_POWER', 67),
     ('GET_ITER', 68),
     ('GET_YIELD_FROM_ITER', 69),
     ('PRINT_EXPR', 70),
     ('LOAD_BUILD_CLASS', 71),
     ('YIELD_FROM', 72),
     ('GET_AWAITABLE', 73),
     ('INPLACE_LSHIFT', 75),
     ('INPLACE_RSHIFT', 76),
     ('INPLACE_AND', 77),
     ('INPLACE_XOR', 78),
     ('INPLACE_OR', 79),
     ('BREAK_LOOP', 80),
     ('WITH_CLEANUP_START', 81),
     ('WITH_CLEANUP_FINISH', 82),
     ('RETURN_VALUE', 83),
     ('IMPORT_STAR', 84),
     ('YIELD_VALUE', 86),
     ('POP_BLOCK', 87),
     ('END_FINALLY', 88),
     ('POP_EXCEPT', 89),
     ('STORE_NAME', 90),
     ('DELETE_NAME', 91),
     ('UNPACK_SEQUENCE', 92),
     ('FOR_ITER', 93),
     ('UNPACK_EX', 94),
     ('STORE_ATTR', 95),
     ('DELETE_ATTR', 96),
     ('STORE_GLOBAL', 97),
     ('DELETE_GLOBAL', 98),
     ('LOAD_CONST', 100),
     ('LOAD_NAME', 101),
     ('BUILD_TUPLE', 102),
     ('BUILD_LIST', 103),
     ('BUILD_SET', 104),
     ('BUILD_MAP', 105),
     ('LOAD_ATTR', 106),
     ('COMPARE_OP', 107),
     ('IMPORT_NAME', 108),
     ('IMPORT_FROM', 109),
     ('JUMP_FORWARD', 110),
     ('JUMP_IF_FALSE_OR_POP', 111),
     ('JUMP_IF_TRUE_OR_POP', 112),
     ('JUMP_ABSOLUTE', 113),
     ('POP_JUMP_IF_FALSE', 114),
     ('POP_JUMP_IF_TRUE', 115),
     ('LOAD_GLOBAL', 116),
     ('CONTINUE_LOOP', 119),
     ('SETUP_LOOP', 120),
     ('SETUP_EXCEPT', 121),
     ('SETUP_FINALLY', 122),
     ('LOAD_FAST', 124),
     ('STORE_FAST', 125),
     ('DELETE_FAST', 126),
     ('RAISE_VARARGS', 130),
     ('CALL_FUNCTION', 131),
     ('MAKE_FUNCTION', 132),
     ('BUILD_SLICE', 133),
     ('MAKE_CLOSURE', 134),
     ('LOAD_CLOSURE', 135),
     ('LOAD_DEREF', 136),
     ('STORE_DEREF', 137),
     ('DELETE_DEREF', 138),
     ('CALL_FUNCTION_VAR', 140),
     ('CALL_FUNCTION_KW', 141),
     ('CALL_FUNCTION_VAR_KW', 142),
     ('SETUP_WITH', 143),
     ('EXTENDED_ARG', 144),
     ('LIST_APPEND', 145),
     ('SET_ADD', 146),
     ('MAP_ADD', 147),
     ('LOAD_CLASSDEREF', 148),
     ('BUILD_LIST_UNPACK', 149),
     ('BUILD_MAP_UNPACK', 150),
     ('BUILD_MAP_UNPACK_WITH_CALL', 151),
     ('BUILD_TUPLE_UNPACK', 152),
     ('BUILD_SET_UNPACK', 153),
     ('SETUP_ASYNC_WITH', 154)]




```python
len(dis.opmap.items()) # numbers of the python instructions
```




    114



而這些bytecode被定義在opcode module中


```python
opcode??
```


```python
dis.cmp_op
```




    ('<',
     '<=',
     '==',
     '!=',
     '>',
     '>=',
     'in',
     'not in',
     'is',
     'is not',
     'exception match',
     'BAD')




```python
dis.hasconst
```




    [100]




```python
dis.hasfree
```




    [135, 136, 137, 138, 148]




```python
dis.hasname
```




    [90, 91, 95, 96, 97, 98, 101, 106, 108, 109, 116]




```python
dis.hasjrel
```




    [93, 110, 120, 121, 122, 143, 154]




```python
dis.hasjabs
```




    [111, 112, 113, 114, 115, 119]




```python
dis.haslocal
```




    [124, 125, 126]




```python
dis.hascompare
```




    [107]



## Ref
Python dis module

<https://docs.python.org/3.7/library/dis.html?module-dis>

stack overflow 對於比較exec和eval的回答

<https://stackoverflow.com/questions/2220699/whats-the-difference-between-eval-exec-and-compile-in-python>

# Python virtual machine implementation
`Python/ceval.c`

```c
PyObject* _Py_HOT_FUNCTION
_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
```

python interpreter main的進入點
```
Py_Main(int arg,wchar_t argv**)
```
python interpreter initiali
```
_Py_InitializeCore
```

PyFrameObject
`Include/frameobject.h`

```c
typedef struct _frame {
    PyObject_VAR_HEAD
    struct _frame *f_back;      /* previous frame, or NULL */
    PyCodeObject *f_code;       /* code segment */
    PyObject *f_builtins;       /* builtin symbol table (PyDictObject) */
    PyObject *f_globals;        /* global symbol table (PyDictObject) */
    PyObject *f_locals;         /* local symbol table (any mapping) */
    PyObject **f_valuestack;    /* points after the last local */
    /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
       Frame evaluation usually NULLs it, but a frame that yields sets it
       to the current stack top. */
    PyObject **f_stacktop;
    PyObject *f_trace;          /* Trace function */

    /* In a generator, we need to be able to swap between the exception
       state inside the generator and the exception state of the calling
       frame (which shouldn't be impacted when the generator "yields"
       from an except handler).
       These three fields exist exactly for that, and are unused for
       non-generator frames. See the save_exc_state and swap_exc_state
       functions in ceval.c for details of their use. */
    PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
    /* Borrowed reference to a generator, or NULL */
    PyObject *f_gen;

    int f_lasti;                /* Last instruction if called */
    /* Call PyFrame_GetLineNumber() instead of reading this field
       directly.  As of 2.3 f_lineno is only valid when tracing is
       active (i.e. when f_trace is set).  At other times we use
       PyCode_Addr2Line to calculate the line from the current
       bytecode index. */
    int f_lineno;               /* Current line number */
    int f_iblock;               /* index in f_blockstack */
    char f_executing;           /* whether the frame is still executing */
    PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
    PyObject *f_localsplus[1];  /* locals+stack, dynamically sized */
} PyFrameObject;
```

## python object
```c

/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA            \
    struct _object *_ob_next;           \
    struct _object *_ob_prev;

#define _PyObject_EXTRA_INIT 0, 0,

#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif

/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD                   PyObject ob_base;

#define PyObject_HEAD_INIT(type)        \
    { _PyObject_EXTRA_INIT              \
    1, type },

#define PyVarObject_HEAD_INIT(type, size)       \
    { PyObject_HEAD_INIT(type) size },

/* PyObject_VAR_HEAD defines the initial segment of all variable-size
 * container objects.  These end with a declaration of an array with 1
 * element, but enough space is malloc'ed so that the array actually
 * has room for ob_size elements.  Note that ob_size is an element count,
 * not necessarily a byte count.
 */
#define PyObject_VAR_HEAD      PyVarObject ob_base;
#define Py_INVALID_SIZE (Py_ssize_t)-1

/* Nothing is actually declared to be a PyObject, but every pointer to
 * a Python object can be cast to a PyObject*.  This is inheritance built
 * by hand.  Similarly every pointer to a variable-size Python object can,
 * in addition, be cast to PyVarObject*.
 */
typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

#define Py_REFCNT(ob)           (((PyObject*)(ob))->ob_refcnt)
#define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)
#define Py_SIZE(ob)             (((PyVarObject*)(ob))->ob_size)


typedef void (*freefunc)(void *);
typedef void (*destructor)(PyObject *);
#ifndef Py_LIMITED_API
/* We can't provide a full compile-time check that limited-API
   users won't implement tp_print. However, not defining printfunc
   and making tp_print of a different function pointer type
   should at least cause a warning in most cases. */
typedef int (*printfunc)(PyObject *, FILE *, int);
#endif
typedef PyObject *(*getattrfunc)(PyObject *, char *);
typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *);
typedef PyObject *(*reprfunc)(PyObject *);
typedef Py_hash_t (*hashfunc)(PyObject *);
typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
typedef PyObject *(*getiterfunc) (PyObject *);
typedef PyObject *(*iternextfunc) (PyObject *);
typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
typedef PyObject *(*allocfunc)(struct _typeobject *, Py_ssize_t);

#ifdef Py_LIMITED_API
typedef struct _typeobject PyTypeObject; /* opaque */
#else
typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; /* For printing, in format "<module>.<name>" */
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

    /* Methods to implement standard operations */

    destructor tp_dealloc;
    printfunc tp_print;
    getattrfunc tp_getattr;
    setattrfunc tp_setattr;
    PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
                                    or tp_reserved (Python 3) */
    reprfunc tp_repr;

    /* Method suites for standard classes */

    PyNumberMethods *tp_as_number;
    PySequenceMethods *tp_as_sequence;
    PyMappingMethods *tp_as_mapping;

    /* More standard operations (here for binary compatibility) */

    hashfunc tp_hash;
    ternaryfunc tp_call;
    reprfunc tp_str;
    getattrofunc tp_getattro;
    setattrofunc tp_setattro;

    /* Functions to access object as input/output buffer */
    PyBufferProcs *tp_as_buffer;

    /* Flags to define presence of optional/expanded features */
    unsigned long tp_flags;

    const char *tp_doc; /* Documentation string */

    /* Assigned meaning in release 2.0 */
    /* call function for all accessible objects */
    traverseproc tp_traverse;

    /* delete references to contained objects */
    inquiry tp_clear;

    /* Assigned meaning in release 2.1 */
    /* rich comparisons */
    richcmpfunc tp_richcompare;

    /* weak reference enabler */
    Py_ssize_t tp_weaklistoffset;

    /* Iterators */
    getiterfunc tp_iter;
    iternextfunc tp_iternext;

    /* Attribute descriptor and subclassing stuff */
    struct PyMethodDef *tp_methods;
    struct PyMemberDef *tp_members;
    struct PyGetSetDef *tp_getset;
    struct _typeobject *tp_base;
    PyObject *tp_dict;
    descrgetfunc tp_descr_get;
    descrsetfunc tp_descr_set;
    Py_ssize_t tp_dictoffset;
    initproc tp_init;
    allocfunc tp_alloc;
    newfunc tp_new;
    freefunc tp_free; /* Low-level free-memory routine */
    inquiry tp_is_gc; /* For PyObject_IS_GC */
    PyObject *tp_bases;
    PyObject *tp_mro; /* method resolution order */
    PyObject *tp_cache;
    PyObject *tp_subclasses;
    PyObject *tp_weaklist;
    destructor tp_del;

    /* Type attribute cache version tag. Added in version 2.6 */
    unsigned int tp_version_tag;

    destructor tp_finalize;

#ifdef COUNT_ALLOCS
    /* these must be last and never explicitly initialized */
    Py_ssize_t tp_allocs;
    Py_ssize_t tp_frees;
    Py_ssize_t tp_maxalloc;
    struct _typeobject *tp_prev;
    struct _typeobject *tp_next;
#endif
} PyTypeObject;
#endif
```

# Design of CPython’s Compiler
`2017-08-25 12:30:51`

In CPython, the compilation from source code to bytecode involves several steps:

* Parse source code into a parse tree (Parser/pgen.c)
* Transform parse tree into an Abstract Syntax Tree (Python/ast.c)
* Transform AST into a Control Flow Graph (Python/compile.c)
* Emit bytecode based on the Control Flow Graph (Python/compile.c)

##  Important Files
* Parser/
    * Python.asdl
        ASDL syntax file
    * asdl.py
        Parser for ASDL definition files. Reads in an ASDL description and parses it into an AST that describes it.
    * asdl_c.py
        “Generate C code from an ASDL description.” Generates Python/Python-ast.c and Include/Python-ast.h.

* Python/
    * Python-ast.c
        Creates C structs corresponding to the ASDL types. Also contains code for marshalling AST nodes (core ASDL types have marshalling code in asdl.c). “File automatically generated by Parser/asdl_c.py”. This file must be committed separately after every grammar change is committed since the __version__ value is set to the latest grammar change revision number.

    * asdl.c
        Contains code to handle the ASDL sequence type. Also has code to handle marshalling the core ASDL types, such as number and identifier. Used by Python-ast.c for marshalling AST nodes.

    * ast.c
        Converts Python’s parse tree into the abstract syntax tree.

    * ceval.c
        Executes byte code (aka, eval loop).

    * compile.c
        Emits bytecode based on the AST.

    * symtable.c
        Generates a symbol table from AST.

    * pyarena.c
        Implementation of the arena memory manager.

    * import.c
        Home of the magic number (named MAGIC) for bytecode versioning

* Include/

    * Python-ast.h
        Contains the actual definitions of the C structs as generated by Python/Python-ast.c. “Automatically generated by Parser/asdl_c.py”.

    * asdl.h
        Header for the corresponding Python/ast.c.

    * ast.h
        Declares PyAST_FromNode() external (from Python/ast.c).

    * code.h
        Header file for Objects/codeobject.c; contains definition of PyCodeObject.

    * symtable.h
        Header for Python/symtable.c. struct symtable and PySTEntryObject are defined here.

    * pyarena.h
        Header file for the corresponding Python/pyarena.c.

    * opcode.h
        Master list of bytecode; if this file is modified you must modify several other files accordingly (see “Introducing New Bytecode”)

* Objects/

    * codeobject.c
        Contains PyCodeObject-related code (originally in Python/compile.c).

* Lib/

    * opcode.py
        One of the files that must be modified if Include/opcode.h is.

## Ref
https://docs.python.org/devguide/compiler.html
http://blog.csdn.net/zhsenl/article/category/2307109/1
https://leanpub.com/insidethepythonvirtualmachine/read#leanpub-auto-the-block-stack
