Python complaints

Tim Peters tim_one at email.msn.com
Wed Dec 1 03:15:09 EST 1999


[Michael Hudson]
> >>> def incr(var):
>         try:
>                 raise 1/0
>         except ZeroDivisionError:
>                 import sys,dis
>                 f = sys.exc_traceback.tb_frame.f_back
>                 loadins = f.f_code.co_code[f.f_lasti - 3:f.f_lasti]
>                 loadop = ord(loadins[0])
>                 name = dis.opname[loadop]
>                 loadarg = ord(loadins[1]) + 256*ord(loadins[2])
>                 vname = f.f_code.co_names[loadarg]
>                 f.f_locals[vname] = f.f_locals[vname] + 1
>
>
> >>> x=1
> >>> incr(x)
> >>> x
> 2

[Jesse D. Sightler]
> Ack, and I though Perl was the only language that made you do stuff
> like that.  :)  Could you please explain this little piece of code?

That Michael is one sick bastard:  he put in these two lines:

                 loadop = ord(loadins[0])
                 name = dis.opname[loadop]

only to throw you off track.  Comment them out, and change the obscure

                 loadarg = ord(loadins[1]) + 256*ord(loadins[2])

to

                 import struct
                 loadarg, = struct.unpack('<H', loadins[1:3])

(don't leave out the first comma!) and I'm sure it will be obvious <wink>.

> It sure looks like byte-code dependant, self-modifying crazyness to me.
> :)

Seriously, you could spend a long time figuring out how it works (when it
does -- it doesn't always).  It is indeed picking apart the byte code,
trying to figure out the name of the variable passed to incr by the caller,
and then modifying the binding of that name in the caller's frame (sometimes
even successfully ...).

At the risk of obfuscating it, here's another way to write the same thing:

    x = x+1

exactly-the-same-number-of-characters<wink>-ly y'rs  - tim






More information about the Python-list mailing list