[Python-3000] defop ?
Phillip J. Eby
pje at telecommunity.com
Thu Nov 23 00:32:38 CET 2006
At 02:06 PM 11/22/2006 -0800, Guido van Rossum wrote:
> > (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.
Well, the idea was that a class decorator can only be invoked inside a
class, so it's a syntax error to invoke it elsewhere. And, there's little
chance of confusing the SyntaxError with some error generated by *running*
the decorator itself, as opposed to merely its positioning.
Anyway, it seemed like a good idea at the time. :)
>I'm guessing that decorate_class squirrels away some info for later?
It introduces a stealth metaclass to the class frame, that will call the
decorator. If there's an existing metaclass in the frame, it invokes it
first to create the class. The devil is in the details, of course, and it
does require that you define any explicit metaclass *before* using any
class decorators, but this is a documented limitation of the DecoratorTools
library.
>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?
Basically, if f_locals contains a '__module__' key that's equal to the
'__name__' in f_globals, although there are some interesting corner cases
involving 'exec' -- the details are in the implementation. The relevant
function is the 'frameinfo(frame)' function which tells you what "kind" of
frame you have.
> Does it work with Jython, IronPython and PyPy?
PyPy should be fine, since it uses the same code objects and
bytecode. IIRC, the others emulate enough of the frame protocol that the
'__module__' and '__name__' checks should be no problem. However, I have
not tried it in any of these. Since this hack requires metaclass support,
there was no point to attempting it in Jython. And when the code was
written, neither IronPython nor PyPy existed yet.
>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().
Sure, there are certainly lots of other ways to implement it! What I
showed was just to demonstrate the *possibility*. If there were defop
syntax, then of course the compiler could simply generate the appropriate
bytecode following the MAKE_CLASS operation. Or MAKE_CLASS could look for
some data inserted into the source dictionary.
decorate_class() is just what I had handy to answer your question - it
should not be confused with being the One Obvious Way to do it is. It's
just proof of possibility (and practical workability, in that it has been
long and widely used successfully with at least CPython).
But, there are still other ways. The compiler could stick
"__owning_class__" attributes on any function defined in a class, and
__addmethod__ could defer actually registering the functions until the
generic function was invoked, thus ensuring that __owning_class__ would be
set first.
In general, if we're allowed to change the implementation of Python, it's
easy to find some way to do it. But you asked for a way to do it in (I
thought) today's Python, so that's what I gave you.
>I'm assuming that's outside the context of the BinaryTree class --
>since inside it, Binarytree is undefined.
Correct.
>Hm, I think this is the first time in this thread that you meant to
>use 'iter', 'len' etc. as "tokens".
I don't understand what you mean. They're objects, and so usable as
tokens. That's why I've also been saying they can also represent
"abilities", with defop being a way to unify their use as generic operation
(e.g. iter()), implementation (i.e. defop iter), and "interface" or ability
(e.g. 'hasmethod(iter,ob)' or something of that sort).
>I think I'd rather change them a
>bit so that they can be objects that actually understand __addmethod__
>and __hasmethod__.
Okay. That's an example of the kind of preference I have no way to divine
ahead of time. If I knew you preferred function attributes for deferred
registration, and to make these objects of a special type, I'd have
proposed it that way. :) My assumption was that changing the type of
Python builtin functions would be considered more "radical" than the idea
of defop, since it requires changing something, rather than just adding.
> > 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?
Yes, assuming that we can call do this with regular functions too. That
is, as long as there's some way to retroactively overload a regular
function. Other than that, I'm not worried about the need to retrofit any
other existing generic function types; their authors will have to change
them for Py3K anyway. :)
More information about the Python-3000
mailing list