Missing operator.call
Is there a reason why the operator module doesn't have an operator.call function? It would seem logical to be able to write: map(operator.call, lst) which calls each object in lst, just like map(operator.neg, lst) negates every object. Of course, operator.call is equivalent to lambda x: x(), but such an equivalence exists for all functions in the operator module. __call__ should also be provided for symmetry with other operators that correspond to special-name methods. If there is interest in this and no reason why it shouldn't be done, I can write up an issue in the tracker and provide a patch.
Hrvoje Niksic wrote:
Is there a reason why the operator module doesn't have an operator.call function?
Python 2.6 adds operator.methodcaller. So you could use operator.methodcaller('__call__'), but that's not really any better than lambda x: x(). A patch to add operator.caller(*args, **kwargs) may be a good idea. Your example would then be: map(operator.caller(), lst) That reads ok to me. I think this reads better though: [callable() for callable in lst] <wink> -Andrew.
Hrvoje Niksic wrote:
Is there a reason why the operator module doesn't have an operator.call function?
My guess is that it was left out because it would have been redundant given the existence of apply() in 2.x. That argument no longer holds in 3.x of course, so operator.call may be a reasonable addition to 3.1 (and then to 2.7 for forward compatibility reasons). I'm somewhere between -0 and +0 though (-0 due to the lack of concrete use cases, +0 because the improved consistency is appealing) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
If there is interest in this and no reason why it shouldn't be done, I can write up an issue in the tracker and provide a patch.
I think there is a tricky design choice to make wrt. argument passing. IIUC, you don't care much about arguments, so you could probably live with def call(o): return o() Somebody proposed that you pass arguments once, and get an "arguments bound" object, i.e. def call(*args, **kwds): def func(o): return o(*args, **kwds) return func Finally, it seems that Guido is advocating an API where arguments get passed along with the callable, i.e. def call(o, *args, **kwds): return o(*args, **kwds) which would make call a synonym for apply (and would also provide for the first definition as a special case). However, with that API, it isn't so easy anymore to pass the same arguments to all callables (unless it is no arguments that you want to pass). Regards, Martin
On Wed, Feb 4, 2009 at 11:48 AM, "Martin v. Löwis" <martin@v.loewis.de> wrote:
If there is interest in this and no reason why it shouldn't be done, I can write up an issue in the tracker and provide a patch.
I think there is a tricky design choice to make wrt. argument passing. IIUC, you don't care much about arguments, so you could probably live with
def call(o): return o()
Somebody proposed that you pass arguments once, and get an "arguments bound" object, i.e.
def call(*args, **kwds): def func(o): return o(*args, **kwds) return func
Finally, it seems that Guido is advocating an API where arguments get passed along with the callable, i.e.
def call(o, *args, **kwds): return o(*args, **kwds)
which would make call a synonym for apply (and would also provide for the first definition as a special case). However, with that API, it isn't so easy anymore to pass the same arguments to all callables (unless it is no arguments that you want to pass).
My version is in line with the other operators in the operator module. The version that binds the arguments and returns a callable is already available as functools.partial. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Hrvoje Niksic wrote:
Is there a reason why the operator module doesn't have an operator.call function?
I've been thinking about proposing an enhancement concerning generators that would entail making "call" a reserved word, so I'd be a little disappointed if this name were used. Maybe apply() could be reinstated and put into the operator module? -- Greg
On Thu, Feb 5, 2009 at 9:20 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
I've been thinking about proposing an enhancement concerning generators that would entail making "call" a reserved word, so I'd be a little disappointed if this name were used.
Maybe apply() could be reinstated and put into the operator module?
That would lose the symmetry with __call__. What's so special about your proposal that requires a new keyword? -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum wrote:
What's so special about your proposal that requires a new keyword?
I was thinking about the proposals that are made from time to time for things like yield *foo to yield all the items from a sub-generator. I was also thinking about what could be done to make using generators as coroutines more convenient, and I came up with the idea of a new statement call expr which would be equivalent to for x in expr: yield x This happens to be the same as what "yield *" would do, so it kind of unifies the two issues. -- Greg
Why is "call expr" a more enticing syntax than "yield *expr" ? On Thu, Feb 5, 2009 at 9:31 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Guido van Rossum wrote:
What's so special about your proposal that requires a new keyword?
I was thinking about the proposals that are made from time to time for things like
yield *foo
to yield all the items from a sub-generator. I was also thinking about what could be done to make using generators as coroutines more convenient, and I came up with the idea of a new statement
call expr
which would be equivalent to
for x in expr: yield x
This happens to be the same as what "yield *" would do, so it kind of unifies the two issues.
-- Greg _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum wrote:
Why is "call expr" a more enticing syntax than "yield *expr" ?
I was thinking it would read better when you're using generators as lightweight threads, and you want the one-level-deep nature of generators to be hidden as much as possible. The fact that yielding is going on is not of interest in that situation -- it's just an implementation detail. What you really want to express is calling another function, but without losing your status of coroutine-ness. Another way of thinking about it is that it allows you to abstract out a chunk of code from a generator that contains a 'yield' and put it into another function, and then call it in a way that resembles an ordinary function call as closely as possible. Maybe 'call' isn't the best word for that, but I haven't thought of anything better so far. -- Greg
Greg Ewing writes:
The fact that yielding is going on is not of interest in that situation -- it's just an implementation detail. What you really want to express is calling another function, but without losing your status of coroutine-ness.
But doesn't "yield" in the sense of "yield the right of way" mean exactly that? Or am I not understanding what you mean by retain status as a coreoutine? I don't know if this is an argument for or against using "yield" in this context.
Stephen J. Turnbull wrote:
Greg Ewing writes:
The fact that yielding is going on is not of interest in that situation
But doesn't "yield" in the sense of "yield the right of way" mean exactly that?
I've no problem with using 'yield' when actually giving up control. But the code making the call doesn't think of itself as yielding. The called code may want to yield, but the caller doesn't care about that. It just wants to make the callee do its thing, whatever it is. Ideally the caller would be able to use a normal function call, but Python generators don't work that way. The next best thing is a slightly different form of call syntax. -- Greg
Greg Ewing <greg.ewing <at> canterbury.ac.nz> writes:
I've no problem with using 'yield' when actually giving up control. But the code making the call doesn't think of itself as yielding. The called code may want to yield, but the caller doesn't care about that. It just wants to make the callee do its thing, whatever it is.
Sorry for saying that, but the more I read your explanations, the less I understand them. In any case, using such a generic word as "call" for generator-specific semantics looks highly confusing to me.
On Fri, Feb 6, 2009 at 3:20 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Stephen J. Turnbull wrote:
Greg Ewing writes:
The fact that yielding is going on is not of interest in that situation
But doesn't "yield" in the sense of "yield the right of way" mean exactly that?
I've no problem with using 'yield' when actually giving up control. But the code making the call doesn't think of itself as yielding. The called code may want to yield, but the caller doesn't care about that. It just wants to make the callee do its thing, whatever it is.
Ideally the caller would be able to use a normal function call, but Python generators don't work that way. The next best thing is a slightly different form of call syntax.
The more I read your motivation the less comfortable I am with using "call" for this purpose. It differs in so many details from a regular call that you're doing your potential users a terrible disservice by trying to pretend that it is something which it isn't, or that it isn't something which it is. Those differences may not seem relevant when sketching a solution, but they come back to haunt you when debugging, for example. It would be way too confusing to have "a different form of call" with totally different semantics that nevertheless used the same *terminology* as is used for regular calls. Imagine the confusion happens when a newbie (maybe someone coming from Fortran :-) writes "call foo(x)" instead of just "foo(x)" and their program totally breaks. "But you told me to call foo" will be their rightful excuse. You could go on, but so could I. A -1 it is. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum wrote:
It would be way too confusing to have "a different form of call" with totally different semantics that nevertheless used the same *terminology* as is used for regular calls.
I expect you're right, so I won't argue for calling it "call" any more. I'd still like to find a good name for it, though. The other important thing is that my proposed construct should be usable as an expression, and its value should be whatever is returned by the called generator when it exits. E.g. if we continue spelling it "yield *" for the moment, then def f(): v = yield *g() print v def g(): yield 42 return "spam" for x in f(): pass should end up printing "spam". Would you entertain the idea of a "yield *" expression with those semantics? -- Greg
On Sat, Feb 7, 2009 at 10:04 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
def f(): v = yield *g() print v
def g(): yield 42 return "spam"
Function g violates the current limitation that generators can't return with a value. So can g only be used using "yield *" then, or would that limitation be removed? - Willem
Willem Broekema wrote:
Function g violates the current limitation that generators can't return with a value. So can g only be used using "yield *" then, or would that limitation be removed?
The limitation would be removed, in the interests of making it easier to use generators as coroutines. -- Greg
All of this debate is moot without the foundation of a common library on which we would be building these coroutines. Any proposal of a specific coroutine syntax is worthless without a time and community tested coroutine implementation, which would be subject to the same rigerous inclusion requirements as any other 3rd party library. Only then, some time in the future, would any argument about a specific syntax be worth real consideration. Let's not jump the shark. On Sat, Feb 7, 2009 at 3:16 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Willem Broekema wrote:
Function g violates the current limitation that generators can't return with a value. So can g only be used using "yield *" then, or would that limitation be removed?
The limitation would be removed, in the interests of making it easier to use generators as coroutines.
-- Greg _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/ironfroggy%40gmail.com
-- Read my blog! I depend on your acceptance of my opinion! I am interesting! http://techblog.ironfroggy.com/ Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy
Time to move to this to python-ideas, folks. On Sat, Feb 7, 2009 at 12:26 PM, Calvin Spealman <ironfroggy@gmail.com> wrote:
All of this debate is moot without the foundation of a common library on which we would be building these coroutines. Any proposal of a specific coroutine syntax is worthless without a time and community tested coroutine implementation, which would be subject to the same rigerous inclusion requirements as any other 3rd party library. Only then, some time in the future, would any argument about a specific syntax be worth real consideration.
Let's not jump the shark.
On Sat, Feb 7, 2009 at 3:16 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Willem Broekema wrote:
Function g violates the current limitation that generators can't return with a value. So can g only be used using "yield *" then, or would that limitation be removed?
The limitation would be removed, in the interests of making it easier to use generators as coroutines.
-- Greg _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/ironfroggy%40gmail.com
-- Read my blog! I depend on your acceptance of my opinion! I am interesting! http://techblog.ironfroggy.com/ Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
We already have yield expressions and they mean something else... On Sat, Feb 7, 2009 at 1:04 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Guido van Rossum wrote:
It would be way too confusing to have "a different form of call" with totally different semantics that nevertheless used the same *terminology* as is used for regular calls.
I expect you're right, so I won't argue for calling it "call" any more.
I'd still like to find a good name for it, though. The other important thing is that my proposed construct should be usable as an expression, and its value should be whatever is returned by the called generator when it exits. E.g. if we continue spelling it "yield *" for the moment, then
def f(): v = yield *g() print v
def g(): yield 42 return "spam"
for x in f(): pass
should end up printing "spam".
Would you entertain the idea of a "yield *" expression with those semantics?
-- Greg _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum wrote:
We already have yield expressions and they mean something else...
They don't have a "*" in them, though, and I don't think the existing meaning of yield as an expression would carry over into the "yield *" variant, so there shouldn't be any conflict. But if you think there will be a conflict, or that the similarity would be too confusing, maybe the new construct should be called something else. I'm open to suggestions. -- Greg
On 01:00 am, greg.ewing@canterbury.ac.nz wrote:
Guido van Rossum wrote:
We already have yield expressions and they mean something else...
They don't have a "*" in them, though, and I don't think the existing meaning of yield as an expression would carry over into the "yield *" variant, so there shouldn't be any conflict.
But if you think there will be a conflict, or that the similarity would be too confusing, maybe the new construct should be called something else. I'm open to suggestions.
I'm *already* regretting poking my head into this particular bike shed, but... has anyone considered the syntax 'yield from iterable'? i.e. def foo(): yield 1 yield 2 def bar(): yield from foo() yield from foo() list(bar()) -> [1, 2, 1, 2] I suggest this because (1) it's already what I say when I see the 'for' construct, i.e. "foo then *yield*s all results *from* bar", and (2) no new keywords are required.
glyph@divmod.com schrieb:
On 01:00 am, greg.ewing@canterbury.ac.nz wrote:
Guido van Rossum wrote:
We already have yield expressions and they mean something else...
They don't have a "*" in them, though, and I don't think the existing meaning of yield as an expression would carry over into the "yield *" variant, so there shouldn't be any conflict.
But if you think there will be a conflict, or that the similarity would be too confusing, maybe the new construct should be called something else. I'm open to suggestions.
I'm *already* regretting poking my head into this particular bike shed, but...
has anyone considered the syntax 'yield from iterable'? i.e.
Yes, basically the "yield *" and "yield from" are the two possibilities that come up every once in a while. Would that someone wrote a PEP, so that we can get a decision at some time. Georg -- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.
glyph@divmod.com wrote:
has anyone considered the syntax 'yield from iterable'?
That would be reasonable, too. I don't really have any strong feelings about the syntax at the moment, except that I'd like it to be something reasonably short so that embedding it in an expression is a feasible thing to do. -- Greg
I came up with the idea of a new statement
call expr
I don't think your ideas should stop us from doing the right thing right now, i.e. add operator.call (for symmetry with everything else that is in the operator module). Whether a call keyword gets added to Python remains to be seen; I would expect some opposition if a PEP was written. Regards, Martin
participants (12)
-
"Martin v. Löwis"
-
Andrew Bennetts
-
Antoine Pitrou
-
Calvin Spealman
-
Georg Brandl
-
glyph@divmod.com
-
Greg Ewing
-
Guido van Rossum
-
Hrvoje Niksic
-
Nick Coghlan
-
Stephen J. Turnbull
-
Willem Broekema