The Magick of __call__ (Or, Digging Deeper Than I Ought To)

Chris Angelico rosuav at gmail.com
Fri Apr 1 17:17:54 CEST 2011


On Sat, Apr 2, 2011 at 2:07 AM, Corey Richardson <kb1pkl at aim.com> wrote:
> All callables (things you can foo(bar)) are really just objects that
> implement the __call__ method, as far as I understand. Well then, that
> would appear to make methods themselves callable, so let's do a little
> playing around...

Interesting.

>>> def Foo():
	pass

>>> Foo
<function Foo at 0x011A51F0>
>>> Foo.__call__
<method-wrapper '__call__' of function object at 0x011A51F0>
>>> Foo.__call__.__call__
<method-wrapper '__call__' of method-wrapper object at 0x011BF850>
>>> Foo.__call__.__call__.__call__
<method-wrapper '__call__' of method-wrapper object at 0x011BF8F0>

I'd have thought that it would simply use Foo.__call__ == Foo, for
simplicity. It's not.

>>> a=[Foo]
>>> a.append(a[-1].__call__)
# repeat above line as many times as desired - builds a list of the recursion
>>> a[-1]==a[-2]
False

So at no point does it ever actually cycle onto itself.

>>> import sys
>>> [sys.getsizeof(q) for q in a]
[60, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32]

The function object takes 60 bytes, everything else 32.

>>> [q.__hash__() for q in a]
[18502128, 29287592, 10666040, 29287592, 10666040, 29287592, 10666040,
29287592, 10666040, 29287592, 10666040, 29287592, 10666040, 29287592]

None of the elements compare equal to each other, but apparently
there's only two hash values possible for them!

Fascinating. I don't know that it's any use, but fascinating!

ChrisA



More information about the Python-list mailing list