[Python-3000] defop ?
Phillip J. Eby
pje at telecommunity.com
Wed Nov 22 21:52:21 CET 2006
At 11:52 AM 11/22/2006 -0800, Guido van Rossum wrote:
>Do I understand correctly that the syntax is more like
>
> 'defop' <expr> '(' <args> ')' ':' <suite>
>
>than like
>
> 'defop' NAME '(' <args> ')' ':' <suite>
>
>? (That would need some kind of limitation on the syntax for <expr> so
>that it can't contain a call, or else it would be syntactically
>ambiguous.)
Yes - it should be the same as for decorators or imports, i.e. a possibly
dotted name.
>What kind of object should the expression produce? What methods on it
>are we going to call, with what arguments?
The defop statement (and its decorators if any) would translate to this code:
@<decorators>
def <anonfunc>(<args>):
<suite>
addmethod(<expr>, <anonfunc>, enclosing_class_or_None)
In other words, addmethod() is invoked following completion of the class
suite (if there is one), and passed the decorated anonymous function object.
Now, we could say that addmethod() just calls expr.__addmethod__. This
would work as long as each builtin had its own __addmethod__() that did the
'cls.__special__ = method' work.
However, I personally find it easier to just think of addmethod() as a
generic function, so that you can define methods for it that recognize the
builtin generics and do the right thing. This also doesn't require the
builtins to grow new methods, and thus can be implemented in today's Python
using only Python code. (Like the example that you described as
brain-exploding orange smoke, which was an actual implementation of
addmethod that would work in today's Python 2.x)
But if it's easier for you to conceptualize, let's just say it expects expr
to have an __addmethod__ method.
> I'd love to see an
>explanation that showed how instead of defop we could also use a
>certain decorator. Perhaps
>
> defop <expr> ( <args> ) : <suite>
>
>is equivalent to
>
> @defop(<expr>)
> def _ ( <args> ) : <suite> # The method name is immaterial here
>
>? Then what goes into the defop decorator? And how does this jive with
>it being inside a class? (And what would it do if it wasn't?)
An implementation for today's Python:
from peak.util.decorators import decorate_class
def defop(expr):
def decorate(func):
def do_add(cls):
addmethod(expr, func, cls)
return cls
try:
decorate_class(do_add)
except SyntaxError: # not in a class
do_add(None) # handle top-level function
return decorate
(The 'decorate_class' function applies its argument as a class decorator
for the class its caller is invoked from. This is the same mechanism (and
actual code!) that Zope uses to do in-body class decorators like
'implements()'.) decorate_class raises a SyntaxError if its caller is not
being run directly inside a class body.
And yes, this uses frame magic, and no, it's not fragile, as it knows the
difference between class and non-class frames. The implementation has been
in Zope for a good few years now, likewise Twisted and PEAK. It's also
available as a standalone package from:
http://cheeseshop.python.org/pypi/DecoratorTools
>but how on earth is the defop syntax of the @defop decorator going to
>generate this?
@defop(flattening.flatten)
def flatten_btree(bt:BinaryTree):
# ... do stuff to bt
Of course, this assumes that flattening.flatten.__addmethod__() is smart
enough to pull the type information off the first argument, if the third
addmethod() argument is None.
>A different line of questioning would be to try to understand how
>Phillip's addmethod and hasmethod are supposed to work. I still hope
>someone will explain it to me.
addmethod registers a method with a generic function. The only reason we
even need it as a separate function (as opposed to just assuming a
__hasmethod__) is to allow retrofitting of existing Python objects (such as
iter/len/etc.) as generic functions via __special__ method setting. The
same applies to hasmethod vs. just using __contains__ or something of that
sort.
If you want to treat it as a Py3K only thing and have __hasmethod__ and
__addmethod__ slots for builtin functions, then there's no need to have
actual addmethod/hasmethod functions. But that's sort of like saying we
don't need getattr() any more because we can just use
type(ob).__getattribute__() now! :)
More information about the Python-3000
mailing list