Hacker News new | ask | show | jobs
by PyComfy 3059 days ago
Naive interpretation of the bytecode (not even pre-decoded, just a switch statement). And almost everything is resolved in the dynamic environment. for example,

    a = foo.bar(b)
is actually

    ldict = locals()

    ldict['a'] = ldict['foo'].__getattribute__('bar')(ldict['b'])
1 comments

This is a bit misleading. You suggest that local variables are looked up by name in a dictionary, which is not the case. They are looked up by indexing into a C array, with the index being a constant in the bytecode. That's quite a lot simpler. Here is the corresponding code (look above for the definition of the GETLOCAL macro): https://github.com/python/cpython/blob/fc1ce810f1da593648b4d...

So your code should be more like:

    locals[a_idx] = locals[foo_idx]->__getattribute__('bar')(locals[b_idx])
But this isn't a very good rendering of the thing because it doesn't show the many redundant reference count increment/decrement pairs every time you touch a variable.

(Also, interpreter dispatch uses computed GOTOs instead of the plain switch on C compilers that support it.)

ah sorry. i did

    import dis
    dis.dis("a = foo.bar(b)")
which gave

    1           0 LOAD_NAME                0 (foo)
                2 LOAD_ATTR                1 (bar)
                4 LOAD_NAME                2 (b)
                6 CALL_FUNCTION            1
                8 STORE_NAME               3 (a)
               10 LOAD_CONST               0 (None)
               12 RETURN_VALUE
Ah, OK. Yes, those LOAD_NAMEs are slower than LOAD_FAST. If you put the code into a function, you get this:

    >>> def f(foo, b):
    ...     a = foo.bar(b)
    ... 
    >>> dis.dis(f)
      2           0 LOAD_FAST                0 (foo)
                  3 LOAD_ATTR                0 (bar)
                  6 LOAD_FAST                1 (b)
                  9 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                 12 STORE_FAST               2 (a)
                 15 LOAD_CONST               0 (None)
                 18 RETURN_VALUE
LOAD_FAST is the normal case for locals inside a function. Not sure off the top of my head where LOAD_NAME would be generated in normal usage (i.e. where you don't evaluate code from a string).

Edit: Also, I'm talking about Python 3. Maybe you aren't.