Re: [Python-Dev] Missing operator.call
Andrew Bennetts wrote:
A patch to add operator.caller(*args, **kwargs) may be a good idea. Your example would then be:
map(operator.caller(), lst)
Regarding the name, note that I proposed operator.call (and operator.__call__) because it corresponds to the __call__ special method, which is analogous to how operator.neg corresponds to __neg__, operator.add to __add__, etc. The term "caller" implies creation of a new object that carries additional state, such as method name in operator.methodcaller, item in operator.itemgetter, or attr in operator.attrgetter.
On Wed, Feb 4, 2009 at 05:35, Hrvoje Niksic <hrvoje.niksic@avl.com> wrote:
Andrew Bennetts wrote:
A patch to add operator.caller(*args, **kwargs) may be a good idea. Your example would then be:
map(operator.caller(), lst)
Regarding the name, note that I proposed operator.call (and operator.__call__) because it corresponds to the __call__ special method, which is analogous to how operator.neg corresponds to __neg__, operator.add to __add__, etc. The term "caller" implies creation of a new object that carries additional state, such as method name in operator.methodcaller, item in operator.itemgetter, or attr in operator.attrgetter.
Part of the problem is the term 'call' is an overloaded term. Do you really mean only objects that define __call__? What about objects that define __init__ and thus can be called as well? If you mean the former than you have to make sure the docs are very clear about this; there is a reason we got rid of callable(). If you mean the latter then there is little benefit to the function since ``[x() for x in lst]`` gets you the same result as your map call. -Brett
On Wed, Feb 4, 2009 at 10:25 AM, Brett Cannon <brett@python.org> wrote:
On Wed, Feb 4, 2009 at 05:35, Hrvoje Niksic <hrvoje.niksic@avl.com> wrote:
Andrew Bennetts wrote:
A patch to add operator.caller(*args, **kwargs) may be a good idea. Your example would then be:
map(operator.caller(), lst)
Regarding the name, note that I proposed operator.call (and operator.__call__) because it corresponds to the __call__ special method, which is analogous to how operator.neg corresponds to __neg__, operator.add to __add__, etc. The term "caller" implies creation of a new object that carries additional state, such as method name in operator.methodcaller, item in operator.itemgetter, or attr in operator.attrgetter.
Part of the problem is the term 'call' is an overloaded term. Do you really mean only objects that define __call__? What about objects that define __init__ and thus can be called as well? If you mean the former than you have to make sure the docs are very clear about this; there is a reason we got rid of callable(). If you mean the latter then there is little benefit to the function since ``[x() for x in lst]`` gets you the same result as your map call.
Not sure I follow you here. It's not the __init__ that allows you to do ``x()``, it's the fact that the class declares a __call__, right?
class C(object): ... pass ... C.__call__() <__main__.C object at 0x01A3C370> C() <__main__.C object at 0x02622EB0> str.__call__() '' str() ''
That said, I'm also unconvinced of the utility of operator.call over the equivalent list comprehension. Steve -- I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a tiny blip on the distant coast of sanity. --- Bucky Katt, Get Fuzzy
On Wed, Feb 4, 2009 at 10:43, Steven Bethard <steven.bethard@gmail.com> wrote:
On Wed, Feb 4, 2009 at 10:25 AM, Brett Cannon <brett@python.org> wrote:
On Wed, Feb 4, 2009 at 05:35, Hrvoje Niksic <hrvoje.niksic@avl.com> wrote:
Andrew Bennetts wrote:
A patch to add operator.caller(*args, **kwargs) may be a good idea. Your example would then be:
map(operator.caller(), lst)
Regarding the name, note that I proposed operator.call (and operator.__call__) because it corresponds to the __call__ special method, which is analogous to how operator.neg corresponds to __neg__, operator.add to __add__, etc. The term "caller" implies creation of a new object that carries additional state, such as method name in operator.methodcaller, item in operator.itemgetter, or attr in operator.attrgetter.
Part of the problem is the term 'call' is an overloaded term. Do you really mean only objects that define __call__? What about objects that define __init__ and thus can be called as well? If you mean the former than you have to make sure the docs are very clear about this; there is a reason we got rid of callable(). If you mean the latter then there is little benefit to the function since ``[x() for x in lst]`` gets you the same result as your map call.
Not sure I follow you here. It's not the __init__ that allows you to do ``x()``, it's the fact that the class declares a __call__, right?
class C(object): ... pass ... C.__call__() <__main__.C object at 0x01A3C370> C() <__main__.C object at 0x02622EB0> str.__call__() '' str() ''
I don't think so::
Foo.__call__ <method-wrapper '__call__' of type object at 0x81cee0c> Foo.__call__ = lambda: None Foo.__call__ <unbound method Foo.<lambda>> Foo() <__main__.Foo object at 0xf7f90e8c>
-Brett
I believe the omission of call from the operator module is an oversight, perhaps caused by the existence (when the operator module was created) of apply. Since apply has been removed from 3.0, we should add operator.call (with the same signature) back. It should be a straightforward wrapper around one of the PyObject_Call* functions. Also note that using __call__ can lead to all sorts of problems when looking at classes -- all class objects have a __call__ attribute, because their metaclass (type) has one, but should not be confused with a __call__ method defined in the class. A quick illustration:
class C(object): ... def __call__(self): print "instance call" ... C() <__main__.C object at 0xf7f9052c> C()() instance call C.__call__() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method __call__() must be called with C instance as first argument (got nothing instead) C.__call__(C()) instance call C.__class__.__call__(C) <__main__.C object at 0xf7f9048c>
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Wed, 4 Feb 2009 10:50:47 -0800, Brett Cannon <brett@python.org> wrote:
On Wed, Feb 4, 2009 at 10:43, Steven Bethard <steven.bethard@gmail.com> wrote:
[snip]
Not sure I follow you here. It's not the __init__ that allows you to do ``x()``, it's the fact that the class declares a __call__, right?
class C(object): ... pass ... C.__call__() <__main__.C object at 0x01A3C370> C() <__main__.C object at 0x02622EB0> str.__call__() '' str() ''
I don't think so::
Foo.__call__ <method-wrapper '__call__' of type object at 0x81cee0c> Foo.__call__ = lambda: None Foo.__call__ <unbound method Foo.<lambda>> Foo() <__main__.Foo object at 0xf7f90e8c>
That's because the __call__ special on an instance is ignored, as many specials on new-style instances are ignored. If you change the method where it counts - on type(Foo) in this case - then you see something different. >>> class X(type): ... def __call__(self, *a, **kw): ... print 'X.__call__', a, kw ... return super(X, self).__call__(*a, **kw) ... >>> class Y(object): ... __metaclass__ = X ... >>> Y.__call__ <bound method X.__call__ of <class '__main__.Y'>> >>> Y() X.__call__ () {} <__main__.Y object at 0xb7d0706c> >>> Y.__call__ = lambda: None >>> Y.__call__ <unbound method Y.<lambda>> >>> Y() X.__call__ () {} <__main__.Y object at 0xb7d0706c> >>> X.__call__ = lambda: None >>> Y() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: <lambda>() takes no arguments (1 given) >>> As far as I know, Steven Bethard's point is correct. Jean-Paul
On Wed, Feb 4, 2009 at 10:50 AM, Brett Cannon <brett@python.org> wrote:
On Wed, Feb 4, 2009 at 10:43, Steven Bethard <steven.bethard@gmail.com> wrote:
Not sure I follow you here. It's not the __init__ that allows you to do ``x()``, it's the fact that the class declares a __call__, right?
class C(object): ... pass ... C.__call__() <__main__.C object at 0x01A3C370> C() <__main__.C object at 0x02622EB0> str.__call__() '' str() ''
I don't think so::
Foo.__call__ <method-wrapper '__call__' of type object at 0x81cee0c> Foo.__call__ = lambda: None Foo.__call__ <unbound method Foo.<lambda>> Foo() <__main__.Foo object at 0xf7f90e8c>
Take a look at PyObject_Call in abstract.c. Basically, __call__ is always looked up on the type, something like:
class C(object): ... def __call__(self): ... return 'instance' ... def func(): ... return 'func' ... type(C).__call__(C) <__main__.C object at 0x0263E250> type(C()).__call__(C()) 'instance' type(func).__call__(func) 'func'
Steve -- I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a tiny blip on the distant coast of sanity. --- Bucky Katt, Get Fuzzy
participants (5)
-
Brett Cannon
-
Guido van Rossum
-
Hrvoje Niksic
-
Jean-Paul Calderone
-
Steven Bethard