PEP 312 (and thus 308) implemented with a black magic trick

Michele Simionato mis6 at pitt.edu
Mon Mar 17 22:58:28 CET 2003


Today I had an illumination on how to implement both PEP 312 and 308
in current Python. I think I will share the idea, even if I would *not* 
recommend to use such a dirty trick in production code.

Notice that instead of the proposed colon notation for PEP 312
(:x as a shortcut for lambda :x) I use a tilde notation:

~x as a shortcut for lambda :x

This means that I am changing the semantics of the unary operator 
"~", which is a Bad Thing: but as I said, this is dirty trick ;)

I am not suggesting it. This is simply a proof of concept.

Here there is an example of usage:

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

# example.py; will not work from the interpreter

from ternary import if_, RecognizesImplicitLambdas
from math import sqrt

class C(RecognizesImplicitLambdas):
   def safesqrt(self,x):
        return if_( x>0, ~sqrt(x), ~0) #short-circuiting ternary operator

c=C()
print c.safesqrt(4), c.safesqrt(-4) 

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

The output of this script is 2.0 and 0, therefore
if_( x>0, ~sqrt(x), ~0) is short-circuiting, as wanted.

Here there is the ternary module:

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

# module ternary.py

"PEP 308 and 312 implemented via a metaclass-powered dirty trick"

import inspect,__main__

# the ternary operator:

def if_(cond,f,g):
    "Short circuiting ternary operator implemented via callable expressions"
    if cond: return f()
    else: return g()

# an utility function:

def dedent(block):
    "Dedent a block of code, if need there is"""
    lines=block.splitlines(); firstline=lines[0]
    spaces=len(firstline)-len(firstline.lstrip())
    if not spaces: return block
    return '\n'.join([line[spaces:] for line in lines])

# the metaclass black magic:

class DirtyTrick(type):
    """Cooperative metaclass that looks at the source code of its instances 
    and replaces the string '~' with 'lambda :' before the class creation"""
    def __new__(meta,name,bases,dic):
        for attr in dic.values():
            if inspect.isfunction(attr): 
                code=inspect.getsource(attr)
                if code.find('~')==-1: continue # no '~' found, skip
                code=code.replace('~','lambda :')
                code=dedent(code)+'\n'
                exec code in __main__.__dict__,dic # modifies dic
        return super(DirtyTrick,meta).__new__(meta,name,bases,dic)

# a convenient base class:

class RecognizesImplicitLambdas:
    "Children of this class do recognize implicit lambdas"
    __metaclass__=DirtyTrick

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

I am aware of the limitation of this approach, still it is quite cool:
notice that the metaclass changes the source code on the fly *before* the
class creation and automagically will be invoked for any subclass of
RecognizesImplicitLambdas. 

Quite impressive, IMHO.

Of course, changing the semantics of the language is never a good idea,
still it is impressive that it is a so easy to perform such a black magic. 
Skipping the comments, the ternary module is only 20 lines long!

Python-is-not-as-simple-as-you-could-imagine-ly yours,

-- 
Michele Simionato - Dept. of Physics and Astronomy
210 Allen Hall Pittsburgh PA 15260 U.S.A.
Phone: 001-412-624-9041 Fax: 001-412-624-9163
Home-page: http://www.phyast.pitt.edu/~micheles/




More information about the Python-list mailing list