Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #80222 > unrolled thread
| Started by | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| First post | 2014-11-04 11:12 -0800 |
| Last post | 2014-11-12 11:58 -0700 |
| Articles | 16 — 7 participants |
Back to article view | Back to comp.lang.python
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [Python-Dev] Dinamically set __call__ method Ethan Furman <ethan@stoneleaf.us> - 2014-11-04 11:12 -0800
Re: [Python-Dev] Dinamically set __call__ method John Ladasky <john_ladasky@sbcglobal.net> - 2014-11-06 12:21 -0800
Re: [Python-Dev] Dinamically set __call__ method dieter <dieter@handshake.de> - 2014-11-07 07:59 +0100
Re: [Python-Dev] Dinamically set __call__ method Ethan Furman <ethan@stoneleaf.us> - 2014-11-07 04:58 -0800
Re: [Python-Dev] Dinamically set __call__ method dieter <dieter@handshake.de> - 2014-11-08 07:50 +0100
Re: [Python-Dev] Dinamically set __call__ method Ethan Furman <ethan@stoneleaf.us> - 2014-11-08 11:49 -0800
Re: [Python-Dev] Dinamically set __call__ method Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2014-11-09 11:31 +1300
Re: [Python-Dev] Dinamically set __call__ method Ethan Furman <ethan@stoneleaf.us> - 2014-11-08 19:27 -0800
Re: [Python-Dev] Dinamically set __call__ method Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2014-11-10 00:38 +1300
Re: [Python-Dev] Dinamically set __call__ method Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-11-10 00:14 +1100
Re: [Python-Dev] Dinamically set __call__ method Ethan Furman <ethan@stoneleaf.us> - 2014-11-09 12:16 -0800
Re: [Python-Dev] Dinamically set __call__ method Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-11 00:43 -0700
Re: [Python-Dev] Dinamically set __call__ method Fabio Zadrozny <fabiofz@gmail.com> - 2014-11-12 13:33 -0200
Re: [Python-Dev] Dinamically set __call__ method Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2014-11-13 17:20 +1300
Re: [Python-Dev] Dinamically set __call__ method Fabio Zadrozny <fabiofz@gmail.com> - 2014-11-13 11:38 -0200
Re: [Python-Dev] Dinamically set __call__ method Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-12 11:58 -0700
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2014-11-04 11:12 -0800 |
| Subject | Re: [Python-Dev] Dinamically set __call__ method |
| Message-ID | <mailman.15467.1415128339.18130.python-list@python.org> |
On 11/04/2014 11:01 AM, Roberto Martínez wrote: > Yikes, I didn't realize the difference in inheritance. > > The thing with this is tricky. I need the change in the instance, not in the class, because I have multiple instances > and all of them must have different implementations of __call__. > > The workaround of calling a different method inside __call__ is not valid for my case because I want to change the > *signature* of the function also -for introspection reasons. If you really absolutely positively have to have the signature be correct for each instance, you may to either look at a function creating factory, a class creating factory, or a meta-class. The first option may work if you don't need an actual class, both of the last two options will be creating different classes, probably with one instance each (unless you have several instances which could share the same __call__). -- ~Ethan~
[toc] | [next] | [standalone]
| From | John Ladasky <john_ladasky@sbcglobal.net> |
|---|---|
| Date | 2014-11-06 12:21 -0800 |
| Message-ID | <c25aa612-bff2-4982-8fb9-5b17a866bead@googlegroups.com> |
| In reply to | #80222 |
On Tuesday, November 4, 2014 11:12:31 AM UTC-8, Ethan Furman wrote: > If you really absolutely positively have to have the signature be correct for each instance, you may to either look at a > function creating factory, a class creating factory, or a meta-class. +1. Overriding __call__() within the class definition, over and over again, with different function, looks awkward to me.
[toc] | [prev] | [next] | [standalone]
| From | dieter <dieter@handshake.de> |
|---|---|
| Date | 2014-11-07 07:59 +0100 |
| Message-ID | <mailman.15555.1415343612.18130.python-list@python.org> |
| In reply to | #80342 |
John Ladasky <john_ladasky@sbcglobal.net> writes: > On Tuesday, November 4, 2014 11:12:31 AM UTC-8, Ethan Furman wrote: > >> If you really absolutely positively have to have the signature be correct for each instance, you may to either look at a >> function creating factory, a class creating factory, or a meta-class. > > +1. Overriding __call__() within the class definition, over and over again, with different function, looks awkward to me. A possibility to get the original approach implemented looks like: make "__call__" a descriptor on the class which looks up the real method on the instance.
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2014-11-07 04:58 -0800 |
| Message-ID | <mailman.15560.1415365135.18130.python-list@python.org> |
| In reply to | #80342 |
On 11/06/2014 10:59 PM, dieter wrote: > John Ladasky writes: >> On Tuesday, November 4, 2014 11:12:31 AM UTC-8, Ethan Furman wrote: >> >>> If you really absolutely positively have to have the signature be correct for each instance, you may to either look at a >>> function creating factory, a class creating factory, or a meta-class. >> >> +1. Overriding __call__() within the class definition, over and over again, with different function, looks awkward to me. > > A possibility to get the original approach implemented looks like: > > make "__call__" a descriptor on the class which looks up the real > method on the instance. This still wouldn't get the signatrue correct, though. -- ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | dieter <dieter@handshake.de> |
|---|---|
| Date | 2014-11-08 07:50 +0100 |
| Message-ID | <mailman.15580.1415429455.18130.python-list@python.org> |
| In reply to | #80342 |
Ethan Furman <ethan@stoneleaf.us> writes: > On 11/06/2014 10:59 PM, dieter wrote: >> John Ladasky writes: >>> On Tuesday, November 4, 2014 11:12:31 AM UTC-8, Ethan Furman wrote: >>> >>>> If you really absolutely positively have to have the signature be correct for each instance, you may to either look at a >>>> function creating factory, a class creating factory, or a meta-class. >>> >>> +1. Overriding __call__() within the class definition, over and over again, with different function, looks awkward to me. >> >> A possibility to get the original approach implemented looks like: >> >> make "__call__" a descriptor on the class which looks up the real >> method on the instance. > > This still wouldn't get the signatrue correct, though. Why not? Once the descriptor is resolved, you get the final instance method - with the correct signature.
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2014-11-08 11:49 -0800 |
| Message-ID | <mailman.15584.1415476169.18130.python-list@python.org> |
| In reply to | #80342 |
On 11/07/2014 10:50 PM, dieter wrote: > Ethan Furman <ethan@stoneleaf.us> writes: > >> On 11/06/2014 10:59 PM, dieter wrote: >>> John Ladasky writes: >>>> On Tuesday, November 4, 2014 11:12:31 AM UTC-8, Ethan Furman wrote: >>>> >>>>> If you really absolutely positively have to have the signature be correct for each instance, you may to either look at a >>>>> function creating factory, a class creating factory, or a meta-class. >>>> >>>> +1. Overriding __call__() within the class definition, over and over again, with different function, looks awkward to me. >>> >>> A possibility to get the original approach implemented looks like: >>> >>> make "__call__" a descriptor on the class which looks up the real >>> method on the instance. >> >> This still wouldn't get the signatrue correct, though. > > Why not? Once the descriptor is resolved, you get the final > instance method - with the correct signature. Hmmm... well, it wouldn't be correct on a class lookup, but, yeah, it would be correct for an instance lookup -- and maybe that's good enough for the OP. -- ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2014-11-09 11:31 +1300 |
| Message-ID | <cc7jtiFubltU1@mid.individual.net> |
| In reply to | #80402 |
Ethan Furman wrote:
>>
>>> On 11/06/2014 10:59 PM, dieter wrote:
>>>
>>>> A possibility to get the original approach implemented looks like:
>>>>
>>>> make "__call__" a descriptor on the class which looks up the real
>>>> method on the instance.
>>>
>>> This still wouldn't get the signatrue correct, though.
>>
>> Why not? Once the descriptor is resolved, you get the final
>> instance method - with the correct signature.
>
> Hmmm... well, it wouldn't be correct on a class lookup, but, yeah, it
> would be correct for an instance lookup -- and maybe that's good enough
> for the OP.
Seems to depend on how you get hold of the object you're
inspecting the signature of. I did an experiment:
class C(object):
@property
def __call__(self):
return self.call
def f(x, y):
print("Called f with %s, %s" % (x, y))
c = C()
c.call = f
c(17, 42)
prints:
Called f with 17, 42
This works too:
import inspect
print(inspect.getargspec(c.__call__))
prints:
ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=None)
But
print(inspect.getargspec(c))
doesn't work:
TypeError: <__main__.C object at 0x479250> is not a Python function
(BTW, I'm actually surprised that this technique makes c callable.
There must be more going on that just "look up __call__ in the class
object", because evaluating C.__call__ just returns the descriptor
and doesn't invoking the descriptor mechanism.)
--
Greg
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2014-11-08 19:27 -0800 |
| Message-ID | <mailman.15590.1415503665.18130.python-list@python.org> |
| In reply to | #80407 |
On 11/08/2014 02:31 PM, Gregory Ewing wrote:
>
> Seems to depend on how you get hold of the object you're
> inspecting the signature of. I did an experiment:
>
> class C(object):
>
> @property
> def __call__(self):
> return self.call
>
> def f(x, y):
> print("Called f with %s, %s" % (x, y))
>
> c = C()
> c.call = f
> c(17, 42)
>
> prints:
> Called f with 17, 42
>
> This works too:
>
> import inspect
> print(inspect.getargspec(c.__call__))
>
> prints:
> ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=None)
>
> But
>
> print(inspect.getargspec(c))
>
> doesn't work:
>
> TypeError: <__main__.C object at 0x479250> is not a Python function
>
> (BTW, I'm actually surprised that this technique makes c callable.
> There must be more going on that just "look up __call__ in the class
> object", because evaluating C.__call__ just returns the descriptor
> and doesn't invoking the descriptor mechanism.)
Looks like you found a bug in inspect.getargspec.
And the thing going on is the normal python behavior (in __getattribute__, I believe) of examining the returned
attribute to see if it is a descriptor, and if so invoking it.
--
~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2014-11-10 00:38 +1300 |
| Message-ID | <cc9210Fans4U1@mid.individual.net> |
| In reply to | #80410 |
Ethan Furman wrote: > And the thing going on is the normal python behavior (in > __getattribute__, I believe) of examining the returned attribute to see > if it is a descriptor, and if so invoking it. Only if you look it up through the instance, though. Normally, if you look up an attribute on a class, the descriptor protocol doesn't get triggered. -- Greg
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2014-11-10 00:14 +1100 |
| Message-ID | <545f68a0$0$12993$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #80424 |
Gregory Ewing wrote:
> Ethan Furman wrote:
>> And the thing going on is the normal python behavior (in
>> __getattribute__, I believe) of examining the returned attribute to see
>> if it is a descriptor, and if so invoking it.
>
> Only if you look it up through the instance, though.
> Normally, if you look up an attribute on a class,
> the descriptor protocol doesn't get triggered.
Since this whole thread is about giving instances their own individual
__call__ methods, I don't think that doing the look-up on the class is part
of the requirements :-)
This seems to work for me:
class call_instance(object):
def __get__(self, obj, cls=None):
if cls is None: cls = type(obj)
if obj is None: obj = cls
return obj.my_call
class SomeClass(object):
__call__ = call_instance()
a = SomeClass()
b = SomeClass()
c = SomeClass()
c.eggs = 23
from types import MethodType
a.my_call = lambda x, y=1: x/y
b.my_call = lambda spam: str(spam).upper()
c.my_call = MethodType(lambda self: self.eggs + 1, c)
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2014-11-09 12:16 -0800 |
| Message-ID | <mailman.15605.1415564188.18130.python-list@python.org> |
| In reply to | #80424 |
On 11/09/2014 03:38 AM, Gregory Ewing wrote: > Ethan Furman wrote: >> >> And the thing going on is the normal python behavior (in __getattribute__, I believe) of examining the returned >> attribute to see if it is a descriptor, and if so invoking it. > > Only if you look it up through the instance, though. > Normally, if you look up an attribute on a class, > the descriptor protocol doesn't get triggered. Hrmm, maybe we're not talking about the same thing. I was responding to your comment: > (BTW, I'm actually surprised that this technique makes c callable. > There must be more going on that just "look up __call__ in the class > object", because evaluating C.__call__ just returns the descriptor > and doesn't invoking the descriptor mechanism.) which seems to clash with what you just said. -- ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2014-11-11 00:43 -0700 |
| Message-ID | <mailman.15648.1415691870.18130.python-list@python.org> |
| In reply to | #80407 |
On Sat, Nov 8, 2014 at 3:31 PM, Gregory Ewing <greg.ewing@canterbury.ac.nz> wrote: > (BTW, I'm actually surprised that this technique makes c callable. > There must be more going on that just "look up __call__ in the class > object", because evaluating C.__call__ just returns the descriptor > and doesn't invoking the descriptor mechanism.) But of course it doesn't just lookup C.__call__, because it has to bind the method to the instance before calling it, which means invoking the descriptor protocol. The actual lookup is more like: type(a).__dict__['__call__'].__get__(a, type(a))
[toc] | [prev] | [next] | [standalone]
| From | Fabio Zadrozny <fabiofz@gmail.com> |
|---|---|
| Date | 2014-11-12 13:33 -0200 |
| Message-ID | <mailman.15726.1415806493.18130.python-list@python.org> |
| In reply to | #80407 |
[Multipart message — attachments visible in raw view] — view raw
On Tue, Nov 11, 2014 at 5:43 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote: > On Sat, Nov 8, 2014 at 3:31 PM, Gregory Ewing > <greg.ewing@canterbury.ac.nz> wrote: > > (BTW, I'm actually surprised that this technique makes c callable. > > There must be more going on that just "look up __call__ in the class > > object", because evaluating C.__call__ just returns the descriptor > > and doesn't invoking the descriptor mechanism.) > > But of course it doesn't just lookup C.__call__, because it has to > bind the method to the instance before calling it, which means > invoking the descriptor protocol. The actual lookup is more like: > > type(a).__dict__['__call__'].__get__(a, type(a)) > -- > https://mail.python.org/mailman/listinfo/python-list > As a reference, I recently found a blog post related to that: http://lucumr.pocoo.org/2014/8/16/the-python-i-would-like-to-see/ (the Slots part comments on that). It does seem a bit counter-intuitive that this happens the way it does though, so, can someone from python-dev give some background of why that's the way it is? i.e.: instead of the approach which would seem simpler which would do getattr(a, '__call__') instead of type(a).__dict__['__call__'].__get__(a, type(a)) -- it seems to me it's mostly because of historical reasons, but I'm really curious why is it so (and if maybe it's something which python-dev would consider worth changing in the future -- not sure how much could break because of that though). Thanks and Best Regards, Fabio
[toc] | [prev] | [next] | [standalone]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2014-11-13 17:20 +1300 |
| Message-ID | <ccips8Fs5j8U1@mid.individual.net> |
| In reply to | #80610 |
Fabio Zadrozny wrote: > can someone from python-dev give some background of why > that's the way it is? It's because, with new-style classes, a class is also an instance (of class "type" or a subclass thereof). So without that rule, it would be ambiguous whether a dunder method applied to instances of a class or to the class itself. > and if maybe it's something which python-dev would consider worth > changing in the future -- not sure how much could break because of that > though Something fairly fundamental that would break is classs instantiation! You instantiate a class by calling it, so if a(x) were implemented as a.__call__(x), and class C had a __call__ method, then C() would invoke that method instead of instantiating C. -- Greg
[toc] | [prev] | [next] | [standalone]
| From | Fabio Zadrozny <fabiofz@gmail.com> |
|---|---|
| Date | 2014-11-13 11:38 -0200 |
| Message-ID | <mailman.15774.1415885965.18130.python-list@python.org> |
| In reply to | #80667 |
[Multipart message — attachments visible in raw view] — view raw
On Thu, Nov 13, 2014 at 2:20 AM, Gregory Ewing <greg.ewing@canterbury.ac.nz> wrote: > Fabio Zadrozny wrote: > >> can someone from python-dev give some background of why that's the way it >> is? >> > > It's because, with new-style classes, a class is also an > instance (of class "type" or a subclass thereof). So > without that rule, it would be ambiguous whether a dunder > method applied to instances of a class or to the class > itself. > > > and if maybe it's something which python-dev would consider worth > >> changing in the future -- not sure how much could break because of that >> though >> > > Something fairly fundamental that would break is classs > instantiation! You instantiate a class by calling it, so if > a(x) were implemented as a.__call__(x), and class C had > a __call__ method, then C() would invoke that method > instead of instantiating C. > > Hi Gregory, Thanks for the explanation -- it still does seem a bit surprising from an end-user point of view, but it does make more sense now :) Best Regards, Fabio
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2014-11-12 11:58 -0700 |
| Message-ID | <mailman.15735.1415818783.18130.python-list@python.org> |
| In reply to | #80407 |
On Wed, Nov 12, 2014 at 8:33 AM, Fabio Zadrozny <fabiofz@gmail.com> wrote: > As a reference, I recently found a blog post related to that: > http://lucumr.pocoo.org/2014/8/16/the-python-i-would-like-to-see/ (the Slots > part comments on that). > > It does seem a bit counter-intuitive that this happens the way it does > though, so, can someone from python-dev give some background of why that's > the way it is? i.e.: instead of the approach which would seem simpler which > would do getattr(a, '__call__') instead of > type(a).__dict__['__call__'].__get__(a, type(a)) -- it seems to me it's > mostly because of historical reasons, but I'm really curious why is it so > (and if maybe it's something which python-dev would consider worth changing > in the future -- not sure how much could break because of that though). I'm not "someone from python-dev", but I think it's done to keep the look-up logic predictable and avoid having to call __getattribute__ and __getattr__ when looking up magic methods. For at least __getattribute__ and __getattr__ themselves we *can't* invoke those methods while trying to look them up, so there's a case to be made for consistency in that this way we don't have to remember which magic methods use __getattribute__ and which ones don't. Performance is also part of it, since these methods tend to be invoked frequently.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web