A better self

Alex Martelli aleax at aleax.it
Sat Jul 20 15:59:53 EDT 2002


brueckd at tbye.com wrote:
        ...
>> > 6) Have Python generate the function bodies for you, e.g:
>> > 
>> >    class SomeClass:
>> >      method = MyCoolUnboundMethodMaker('arg:x = y*z + t*arg')
>> 
>> Hmmm...what's that?
> 
> Just an idea - since Python is so dynamic, instead of writing the
> function you write a string describing the function and have another
> function read it and generate a method that does all the 'self.' stuff.
> Obviously you'd have to think it through some, but this is definitely
> possible.
> 
> In the above example, I assume MyCoolUnboundMethodMaker would read
> the string, and use it to generate a string like this:
> 
> '''def NewMethod(self, arg):
>     self.x = self.y * self.z + self.t * arg
> '''
> 
> after which it would exec the string and then do a 'return NewMethod', and
> bingo, your class now has a method that performs that operation. It'd take
> some work to get it right the first time, but from then on you could reuse
> it for all your numeric work.

Indeed, code generation is not a bad idea.  However, I think I
would take a different approach to it, based on hacking bytecode
in a metaclass rather than generating and compiling source.  It's
just py-in-the-sky musing, but -- imagine being able to code, e.g.:

class Myself(Selfer):
    __slots__ = 'x y z'.split()
    def __init__(ax, ay, az):
        x, y, z = ax, ay, az
    def compute():
        return x**y/z

and have type(Selfer), e.g. SelferMeta, tweak the code so it's
just as if you had put self in all the needed places.  It should
be feasible (with the obvious limitations -- all the slot names
become reserved as variable names and you can't use them for any
argument, global, local, etc).

The point is that SelferMeta.__new__ gets to look at all of
class Myself's dictionary *and tamper with it as needed* before
delegating the rest to class type.  Specifically, it would get
to look at the various methods, already compiled down to
bytecode... and change the bytecode as needed, i.e., each
of the various LOAD_GLOBAL, STORE_FAST, LOAD_FAST, would be
checked to see if the name it refers to is in __slots__, and,
if so, transformed into LOAD_FAST+LOAD_ATTR, or LOAD_FAST+
STORE_ATTR.  Of course, all the arguments of the various
JUMP_* operators would have to be adjusted as the code's
length changes.  Hmmm, would you want to allow calling methods
by bare-name, too, or would self.name() be still required there?
No matter -- it's your language, design it as you wish, of
course.  Implementation is pretty obvious anyway.  Oh I was
almost forgetting -- insert a first argument named 'self' if
not already present, and then change any LOAD_GLOBAL for 'self'
to LOAD_FAST instead, of course.

Sounds like about a week's worth of serious hacking, and all
in Python -- no C needed.

Me, I like 'self' -- but, as you see, those who dislike it
have only a modest effort to spend to make it optional in
their own classes.  Not right now (I should be writing the
Nutshell, darn, NOT reading and writing on c.l.py...!!!),
but when the Nutshell's done I'll be available for only
moderately outrageous hourly rates (Strakt only takes 40
hours a week of my time, as Agile development principles
dictate), and I'm quite willing to make a fixed price bid
for this if we can nail down the specs to something easy
to implement this way.  I'm sure lots more people who are
comfortable hacking on bytecode will also be happy to bid
(assuming every self-hater is unable or unwilling to dirty
his or her hands with this approach).

The point is: custom metaclasses allow you to do a LOT of
things more productively than by whining on c.l.py.  Not
all, by a long shot, since a class with a custom meta must
still be syntactically valid Python (what you can't
express that way you must hack into docstrings, or via
naming-conventions, and the like).  But a heck of a *LOT*.

So why not 'import dis' and start studying bytecode on
small examples, and how you could hack on it?  DIY is
cheaper and more fun -- and you're sure to learn a lot
even if you end up throwing the results away!-)


Alex




More information about the Python-list mailing list