On Wed, Aug 11, 2010 at 6:03 PM, Greg Ewing email@example.com wrote:
is evaluated by first checking whether the object ``f`` implements a ``__cocall__`` method. If it does, the cocall expression is equivalent to
yield from f.__cocall__(*args, **kwds)
except that the object returned by __cocall__ is expected to be an iterator, so the step of calling iter() on it is skipped.
I think I'd like to see this exist for a while as:
yield from f.cocall(*args, **kwds)
for a while after PEP 380 is implemented before it is given syntactic sugar.
Similar to my other suggestion, a @cofunction decorator could easily provide a cocall method without implementing __call__.
The compiler wouldn't pick up usages of f.cocall() without yield from with this approach, but tools like pychecker and pylint could certainly warn about it.
If ``f`` does not have a ``__cocall__`` method, or the ``__cocall__`` method returns ``NotImplemented``, then the cocall expression is treated as an ordinary call, and the ``__call__`` method of ``f`` is invoked.
Objects which implement __cocall__ are expected to return an object obeying the iterator protocol. Cofunctions respond to __cocall__ the same way as ordinary generator functions respond to __call__, i.e. by returning a generator-iterator.
You want more than the iterator protocol - you want the whole generator API (i.e. send() and throw() as well as __next__()).
Certain objects that wrap other callable objects, notably bound methods, will be given __cocall__ implementations that delegate to the underlying object.
If you use a @cofunction decorator, you can define your own descriptor semantics, independent of those for ordinary functions.
The use of a decorator instead of ``codef`` was also suggested, but the current proposal makes this unnecessary as well.
I'm not sure that is really an advantage, given that using a decorator gives much greater control over the way cofunctions behave.
It has been questioned whether some combination of decorators and functions could be used instead of a dedicated ``cocall`` syntax. While this might be possible, to achieve equivalent error-detecting power it would be necessary to write cofunction calls as something like
yield from cocall(f)(args)
making them even more verbose and inelegant than an unadorned ``yield from``. It is also not clear whether it is possible to achieve all of the benefits of the cocall syntax using this kind of approach.
As far as I can see, the only thing dedicated syntax adds is the ability for the compiler to detect when a cofunction is called without correctly yielding control. But pylint/pychecker would still be able to do that with a decorator based approach.
I'd really want to see a nice clean @cofunction decorator approach based on PEP 380 seriously attempted before we threw our hands up and said new syntax was the only way.