[Python-3000] defop ?

Guido van Rossum guido at python.org
Wed Nov 22 23:06:33 CET 2006


On 11/22/06, Phillip J. Eby <pje at telecommunity.com> wrote:
> 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)

Where is it gonna get the enclosing class? That object hasn't been
created yet at the time defop executes.

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

OK, this I can understand. Thanks for being concrete.

> However, I personally find it easier to just think of addmethod() as a
> generic function,

yes, but that's you've had generic functions on your brain for a year
or more now. For the rest of us, saying "it calls expr.__addmethod__"
is a lot easier to process. And you've already shown earlier that
these two are pretty much equivalent. :-)

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

Working code can explode heads too. :-)

> But if it's easier for you to conceptualize, let's just say it expects expr
> to have an __addmethod__ method.

Yes, thank you, this helps.

> 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

Alas, this is all smoke and mirrors again for me, since I don't know
what decorate_class does, or why on earth it would raise SyntaxError.

How does this address the problem that the class doesn't yet exist?

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

That's a bizarre use of that exception.

I'm guessing that decorate_class squirrels away some info for later?
Everything here seems designed to hide the implementation details,
which is great for actual use, but kills understanding of the
mechanism. :-(

> And yes, this uses frame magic, and no, it's not fragile, as it knows the
> difference between class and non-class frames.

Wow. How can you tell? Does it work with Jython, IronPython and PyPy?

I still find it fragile somehow -- or at least severely hackish. I
like the other proposal (where it puts a special attribute on the
function object which is then found by the type) better, it doesn't
require sys._getframe().

> 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

I'm assuming that's outside the context of the BinaryTree class --
since inside it, Binarytree is undefined.

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

Assuming we have optional argument annotations that would be nice.

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

Hm, I think this is the first time in this thread that you meant to
use 'iter', 'len' etc. as "tokens". I think I'd rather change them a
bit so that they can be objects that actually understand __addmethod__
and __hasmethod__.

> If you want to treat it as a Py3K only thing

I do, that's why we're discussing it here.

> and have __hasmethod__ and
> __addmethod__ slots for builtin functions,

I have no problem with making those builtins that are generic
functions into instances of some other class. I don't think all 50+
builtins should become generic methods.

> 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!  :)

But I think you're really proposing an addmethod builtin that calls an
__addmethod__ method, right? That sounds fine to me if we can work out
the rest of the details.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-3000 mailing list