Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

3 views
Skip to first unread message

Michele Simionato

unread,
Mar 17, 2003, 4:58:28 PM3/17/03
to
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/

sism...@hebmex.com

unread,
Mar 17, 2003, 5:06:24 PM3/17/03
to
> From: mi...@pitt.edu [mailto:mi...@pitt.edu]
> Sent: Monday, March 17, 2003 3:58 PM
>
> [..evil...snipped..]
>

You evil, evil man....

But nontheless, very impressive!! :-)

This give me ideas....

;-)

Thanks!!

-gustavo

Michele Simionato

unread,
Mar 17, 2003, 5:18:30 PM3/17/03
to

Hey!

I don't want to be taken for responsibile if people start
playing this kind of tricks ... I want still to be able to
read Python code!

;-)

Erik Max Francis

unread,
Mar 17, 2003, 7:03:33 PM3/17/03
to
Michele Simionato wrote:

> 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 ;)

How does this suggestion different from the use of a single colon in PEP
312, except that this invalidates a previously existing legitimate
behavior? It has exactly the same benefits and drawbacks of PEP 312,
except with the introduction of an additional drawback.

Furthermore, if you change the meaning of ~, what operator now becomes
used to represent bitwise negation?

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ It is human nature to think wisely and act foolishly.
\__/ Anatole France
Church / http://www.alcyone.com/pyos/church/
A lambda calculus explorer in Python.

Steven Taschuk

unread,
Mar 17, 2003, 8:54:53 PM3/17/03
to
Quoth Erik Max Francis:
> Michele Simionato wrote:
[...]

> > ~x as a shortcut for lambda :x
[...]

> How does this suggestion different from the use of a single colon in PEP
> 312, except that this invalidates a previously existing legitimate
> behavior? It has exactly the same benefits and drawbacks of PEP 312,
> except with the introduction of an additional drawback.

I wonder if you read the implementation, which emphasizes the
"dirty trick" aspect, and strongly suggests taking Simionato's
post as a joke.

But, if you insist, two unique advantages: first, the technique
requires no language changes whatsoever; second, it enables the
use of the special syntax on a class-by-class basis.

> Furthermore, if you change the meaning of ~, what operator now becomes
> used to represent bitwise negation?

Any code not in a class hacked as in Simionato's post can continue
to use ~ as before.

--
Steven Taschuk stas...@telusplanet.net
"I'm always serious, never more so than when I'm being flippant."
-- _Look to Windward_, Iain M. Banks

Jack Diederich

unread,
Mar 17, 2003, 7:21:05 PM3/17/03
to
On Mon, Mar 17, 2003 at 04:03:33PM -0800, Erik Max Francis wrote:
>
> Furthermore, if you change the meaning of ~, what operator now becomes
> used to represent bitwise negation?

I've expressed elsewhere, moving bitwise operators to a 'bit' module would
be pythonic IMO. The number of times you have to do bitwise operation in
python it tiny; bitwise operations are low level operations.

That said, it is unlikely to be changed because moving them would be more
of a pain that keeping them as-is.

-jackdied

Raymond Hettinger

unread,
Mar 17, 2003, 8:19:24 PM3/17/03
to
> 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

Dear Dr. Strangelove,

You are a dangerous man.
I'm glad you're on our side.
You are on our side, aren't you?

curiouser-and-curiouser-ly yours,


Raymond Hettinger


Sean Ross

unread,
Mar 17, 2003, 8:38:22 PM3/17/03
to
Hi.

"Erik Max Francis" <m...@alcyone.com> wrote in message
news:3E766255...@alcyone.com...


>
> How does this suggestion different from the use of a single colon in PEP

312, ...


Actually, it wasn't a suggestion, it was merely a hack. The OP was just
trying to see if it could be done,
as they stated in their post...

"Michele Simionato" <mi...@pitt.edu> wrote...


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

They were not suggesting an alternative syntax to PEP312, they were playing
around with code.
'~' just happens to be easier than ':' to intelligently isolate and replace
in Python code because it
has fewer possible uses/meanings.

"Erik Max Francis" <m...@alcyone.com> wrote:
>...except that this invalidates a previously existing legitimate
> behavior? ...

This is beside the point, but while we're here:

Actually, it only 'overrides' the previously existing behaviour of '~'
inside of a class that inherits from
'RecognizesImplicitLambdas'. Meaning the behaviour of '~' will remain
unaffected in any class that
does not subclass 'RecognizesImplicitlambdas', and in every other scope,
other than inside a class that
_does_ subclass 'RecognizesImplicitlambdas'.

Meaning, if you don't use it, nothing is changed.
And, if you do use it, you'll just have to ensure that there are no
requirements for bitwise negation
inside of your class. i.e.,
If you want to soak yourself in gasoline, go right ahead.
And if you don't, don't. But, if you do,
and you then insist on lighting matches...well...don't come
crying to me...


"Erik Max Francis" <m...@alcyone.com> wrote:
> Furthermore, if you change the meaning of ~, what operator now becomes
> used to represent bitwise negation?

That's really not the point. If the OP were suggesting that that his hack be
added to the language,
then this would be a valid concern. However, no such suggestion has been
made (in fact, quite
the opposite).

"Michele Simionato" <mi...@pitt.edu> wrote...
> ...changing the semantics of the language is never a good idea...

The OP was not suggesting that their code be used, they were simply
presenting the community with
a neat little toy. And, they even took the time to label it with "Choking
Hazard" tags.


Sean Ross

unread,
Mar 17, 2003, 8:44:57 PM3/17/03
to

"Sean Ross" <sr...@connectmail.carleton.ca> wrote in message
news:GLuda.3364$544.3...@news20.bellglobal.com...

> If you want to soak yourself in gasoline, go right ahead.
> And if you don't, don't. But, if you do,
> and you then insist on lighting matches...well...don't
come
> crying to me...
>

A more apt analogy would be:
"If you insist on turning a match into a glass of water, don't
expect to go around lighting candles with it"

Steven Taschuk

unread,
Mar 18, 2003, 2:44:09 AM3/18/03
to
Quoth Sean Ross:
[...]

> '~' just happens to be easier than ':' to intelligently isolate and replace
> in Python code because it
> has fewer possible uses/meanings.

Imho the more important factor is that the code using ~ in the
black magic way can be compiled by the stock compiler as is
(though the result of that compilation is never used).

--
Steven Taschuk o- @
stas...@telusplanet.net 7O )
" (

Michael Hudson

unread,
Mar 18, 2003, 7:27:10 AM3/18/03
to
mi...@pitt.edu (Michele Simionato) writes:

> 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.

Do you know about my bytecodehacks? They might appeal to your
hackerish instincts...

I once proposed an "explosive license" for things like this: if you
use them in production code, your shoes explode.

Cheers,
M.

--
42. You can measure a programmer's perspective by noting his
attitude on the continuing vitality of FORTRAN.
-- Alan Perlis, http://www.cs.yale.edu/homes/perlis-alan/quotes.html

Michele Simionato

unread,
Mar 18, 2003, 9:56:46 AM3/18/03
to
"Sean Ross" <sr...@connectmail.carleton.ca> wrote in message news:<GLuda.3364$544.3...@news20.bellglobal.com>...
> Hi.
>
> "Erik Max Francis" <m...@alcyone.com> wrote in message
> news:3E766255...@alcyone.com...
> >
> > How does this suggestion different from the use of a single colon in PEP
> 312, ...
>
>
> Actually, it wasn't a suggestion, it was merely a hack. The OP was just
> trying to see if it could be done,
> as they stated in their post...
>
> "Michele Simionato" <mi...@pitt.edu> wrote...
> > I am not suggesting it. This is simply a proof of concept.
>
> They were not suggesting an alternative syntax to PEP312, they were playing
> around with code.
> '~' just happens to be easier than ':' to intelligently isolate and replace
> in Python code because it
> has fewer possible uses/meanings.
>

Beside that, there is the problem that ":x" is not a valid Python
expression,
whereas "~x" is grammatically correct. Using ":x" would give a syntax
error,
using "~x" makes happy the interpreter, instead. At this point my
truly evil metaclass can fool it ;)

continuing-to-explore-Python-dark-side-ly yours,

Michele

Alex Martelli

unread,
Mar 18, 2003, 10:07:10 AM3/18/03
to
Erik Max Francis wrote:
...

> Furthermore, if you change the meaning of ~, what operator now becomes
> used to represent bitwise negation?

Why, the
-1^
"operator", of course -- or the
-1-
"operator", as a roughly equivalent alternative -- after all,

assert ~x == -1^x == -1-x

innit...? Using ^ has the advantage of raising TypeError when ~ would
(I think), while - would be more permissive.


Alex

Michele Simionato

unread,
Mar 18, 2003, 10:50:17 AM3/18/03
to
Few months ago there was a debate on c.l.p. about adding macros to Python [1].
Then everybody started pointing out that macros are evil because they
allow the programmamer to change the *syntax* of the language.

With this example I wanted to point out (using the form of a joke and of
a clever [2] hack) that we already have metaclasses, that potentially are
*much more evil* than macros. Metaclasses allow to change the *semantics* of
the language (WYSINWYG: what you see is not what you get).
Changing the source code on the fly is only a particular way of
changing the semantics, maybe more evidently dirtier than others.

The problem (or advantage, depending on your point of view) is that
there are many other ways of changing the semantics: imagine a metaclass
that wraps all the methods of a class with arbitrary functions and all
the attributes with properties involving arbitrary functions: the
final effect is that you read some code and Python actually sees a
completely different thing.

I remember Peter Hansen complaining about properties, because you could
write an apparently innocuos statement like 'c.x=1' and have any kind
of side effects, including activating a nuclear weapon (of something like
that, IIRC, it was some time ago ;). There are plenty of ways of doing
such dirty tricks in Python 2.2+, much more than in previous versions. [3]

Fortunately, the dark side of Python is well covered under a clean surface,
and you could use the language for a long time never suspecting its existence.
Also, there is little risk that the average programmer would discover all
the secrets of metaclasses (maybe ill documented on purpose ;)

Nevertheless, the post was meant to say:

ATTENTION! ATTENTION!

plain, usual, apparently innocuos standard Python already contains a fair
amount of black magic, so much, in effect, that it is possible to implement
PEP 312 and 308 in 20 lines! (there are some limitations, actually, but still
the 20 line implementation would work for most code).

Python is a very strange language: on the surface it is very constraining
(you are even forced to indent you code!), but under the hood it gives to the
programmer an incredible amount of freedom.

I think it is extremely difficult to figure out all the deepest consequences
of the new Python object model, and all its possible outcomes. For the
moment, I content myself with exploring, learning and *not* applying :)

Michele

Notes:

[1] I am not saying I want macros added to Python
[2] Clever is not the same than wise, as Laura Chreighton
pointed out some time ago.
[3] I am not saying I want these controversial features removed.

P.S.

"Raymond Hettinger" <vze4...@verizon.net> wrote in message news:<wuuda.50506$68.3...@nwrdny01.gnilink.net>...


> Dear Dr. Strangelove,
>
> You are a dangerous man.
> I'm glad you're on our side.
> You are on our side, aren't you?
>
> curiouser-and-curiouser-ly yours,
>
>
> Raymond Hettinger

I am the kind of person who likes more Darth Vader than Luke
Skywalker ... ;)

Max M

unread,
Mar 18, 2003, 11:41:15 AM3/18/03
to
Michele Simionato wrote:

> With this example I wanted to point out (using the form of a joke and of
> a clever [2] hack) that we already have metaclasses, that potentially are
> *much more evil* than macros. Metaclasses allow to change the *semantics* of
> the language (WYSINWYG: what you see is not what you get).


I just wanted to add that you should probably call that WYGIWYG instead
of WYSINWYG.

You know WYGIWYG like in the old printer and Wordperfect days.

"What You Get Is What You Get": Wanna see how it looks printed out? Just
print it out and look at the paper.

Wanne see what this code does? Just run it and see what happens ;-)

--

hilsen/regards Max M Rasmussen, Denmark

http://www.futureport.dk/
Fremtiden, videnskab, skeptiscisme og transhumanisme

Chermside, Michael

unread,
Mar 18, 2003, 11:07:11 AM3/18/03
to
I just wanted to say that I'm really impressed.

It's pure evil, of course, but nonetheless very beautiful and
astoundingly simple.

For some reason I'm more disturbed by the mis-use of operator
overloading than by the metaclass which modifies code...
perhaps because I've been burned by the former before (in C++).

-- Michael Chermside


sism...@hebmex.com

unread,
Mar 18, 2003, 11:13:16 AM3/18/03
to
> From: Chermside, Michael [mailto:mcher...@ingdirect.com]
> Sent: Tuesday, March 18, 2003 10:07 AM

Perhaps, instead of using "~" as a marker for "lazy-evaluation",
"~~" can be used. It's easy to see, not too "noisy", it's
syntacticly correct, and very improbable to be used like that.

:-)

-gus

Greg Ewing (using news.cis.dfn.de)

unread,
Mar 18, 2003, 8:17:49 PM3/18/03
to
Michele Simionato wrote:
> I remember Peter Hansen complaining about properties, because you could
> write an apparently innocuos statement like 'c.x=1' and have any kind
> of side effects, including activating a nuclear weapon (or something like
> that

PSU Public Announcement
-----------------------

Although it is unusual for the PSU to make public statements,
we have decided to do so on this occasion to allay any fears
that the above post may have engendered in the populance.

We would like to assure everyone that we have been assiduous
in our efforts to ensure that our country's nuclear arsenal
cannot be accidentally activated by any such occurrence.
A nuclear strike can only be initiated by four Python
programmers executing four different innocuous-looking
expressions simultaneously in geographically separated
locations.

The particular expressions required are changed on a
daily basis, and held securely in encrypted form scribbled
on a piece of paper kept under the President's pillow.
Last Thursday, for example, they were x+=3, int(42),
import re and s=s[::-1]. (We cannot, of course, reveal
today's codes, otherwise we would have to use the time
machine to go back and eliminate your grandparents.)

We hope that this information will set the public's mind
at rest.

Finally, as always, the PSU does not exist, and we do not
have a time machine. Please look into the light. <zap>

[End Public Announcement]

Tim Churches

unread,
Mar 18, 2003, 9:53:26 PM3/18/03
to
Greg Ewing (using news.cis.dfn.de) <m...@privacy.net> wrote:
> PSU Public Announcement
> -----------------------
>
> Although it is unusual for the PSU to make public statements,
> we have decided to do so on this occasion to allay any fears
> that the above post may have engendered in the populance.
>
> We would like to assure everyone that we have been assiduous
> in our efforts to ensure that our country's nuclear arsenal
> cannot be accidentally activated by any such occurrence.

Are you the Greg Ewing of Pyrex fame, from Canterbury University in New
Zealand? If so, I didn't think New Zealand had a nuclear arsenal. In fact, I thought
NZ was rather laudably opposed to anyone have such horrible things. I see your
email address is from Germany. I didn't think Germany had nukes, either. Maybe
you're an American after all.

> A nuclear strike can only be initiated by four Python
> programmers executing four different innocuous-looking
> expressions simultaneously in geographically separated
> locations.

Please tell me that those four Python programmers are not now sitting with their
fingers hovering over the Enter key, waiting for the word from you-know-who.
Given the latest US defense policy which talks about pre-emptive strikes and the
need for "usable" nukes, and given the evident US propensity for military
adventurism, this scenario suddenly seems like a real possibility, particularly if
things don't go as smoothly in the next few days as Rumsfeld has no doubt
promised George Dubya they will.

Tim C

Greg Ewing (using news.cis.dfn.de)

unread,
Mar 18, 2003, 10:29:31 PM3/18/03
to
Tim Churches wrote:
> Are you the Greg Ewing of Pyrex fame, from Canterbury University in New
> Zealand? If so, I didn't think New Zealand had a nuclear arsenal.

I am, but on that occasion the PSU was using me to channel
their thoughts (they frequently pick random people from around
the world for that, to better obfuscate their identity, or
lack thereof). It seems that "our country" in their
announcement is meant to refer to the USA.

> I see your email address is from Germany.

Is it? That's news to me! I always thought .nz referred to
New Zealand... Has the PSU been messing around with the
domain name system again? Things got terribly confused last
time they did that.

> Please tell me that those four Python programmers are not now sitting with their
> fingers hovering over the Enter key, waiting for the word from you-know-who.

I certainly hope not, but... only George and the PSU
know...

--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg

Andrew Bennetts

unread,
Mar 19, 2003, 6:03:45 AM3/19/03
to
On Mon, Mar 17, 2003 at 01:58:28PM -0800, Michele Simionato wrote:
> 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.

Nasty. :)

So, who's going to be the first to implement ++x using this technique?

-Andrew.


Michael Hudson

unread,
Mar 19, 2003, 8:46:36 AM3/19/03
to
Tim Churches <tc...@optushome.com.au> writes:

> Please tell me that those four Python programmers are not now
> sitting with their fingers hovering over the Enter key, waiting for
> the word from you-know-who.

Nah, we're waiting for Kaz:

http://dspace.dial.pipex.com/town/green/gfd34/art/bloopers.html

Cheers,
M.

--
Enlightenment is probably antithetical to impatience.
-- Erik Naggum, comp.lang.lisp

Terry Reedy

unread,
Mar 19, 2003, 12:21:24 PM3/19/03
to

"Andrew Bennetts" <andrew-p...@puzzling.org> wrote in message
news:mailman.1048071128...@python.org...

If, as I understand, this meta technique relies on source text, this
should work. But not if it looks at code:

>>> def f(): return ++1
...
>>> import dis
>>> dis.dis(f)
0 SET_LINENO 1

3 SET_LINENO 1
6 LOAD_CONST 1 (1)
9 UNARY_POSITIVE
10 RETURN_VALUE
11 LOAD_CONST 0 (None)
14 RETURN_VALUE

Compiler seems to optimize away second unary positive.

Terry J. Reedy


Anders J. Munch

unread,
Mar 20, 2003, 4:53:53 AM3/20/03
to
"Terry Reedy" <tjr...@udel.edu> wrote:
>
> If, as I understand, this meta technique relies on source text, this
> should work. But not if it looks at code:
>
> >>> def f(): return ++1
> ...
[...]

>
> Compiler seems to optimize away second unary positive.
>

The second unary positive is treated as part of the integer literal.
Try instead disassembling

def f(x): ++x

You can have as many UNARY_POSITIVEs as you like.

- Anders

Martijn Faassen

unread,
Mar 21, 2003, 6:11:29 AM3/21/03
to
"Greg Ewing (using news.cis.dfn.de)" <m...@privacy.net> wrote:
> Tim Churches wrote:
>> Are you the Greg Ewing of Pyrex fame, from Canterbury University in New
>> Zealand? If so, I didn't think New Zealand had a nuclear arsenal.
>
> I am, but on that occasion the PSU was using me to channel
> their thoughts (they frequently pick random people from around
> the world for that, to better obfuscate their identity, or
> lack thereof). It seems that "our country" in their
> announcement is meant to refer to the USA.

Can't have been the real PSU then, as the real PSU is a cross-time
organization and "our country" would mean

Drew Perttula

unread,
Mar 26, 2003, 4:00:14 PM3/26/03
to
Andrew Bennetts <andrew-p...@puzzling.org> wrote in message news:<mailman.1048071128...@python.org>...

>

> So, who's going to be the first to implement ++x using this technique?
>

To my knowledge, it's exarkun. He wrote
http://intarweb.us:8080/evil/increment.py a long
time ago.

Let the directory name in the URL serve
as the "do not use this" indicator. I repeat, for
the benefit of any C programmers who think there's
something relevant about ++ for Python: ++ incrementing
is unclear, non-useful, and not part of Python's syntax
despite what hacks can make it appear to work. Do not
use the increment.py module.

0 new messages