I think you're fighting windmills. Like most special operations (e.g. __add__), a __call__ attribute on the object does not work, i.e. it does not make the object callable. E.g. $ python3 Python 3.5.0a2 (v3.5.0a2:0337bd7ebcb6, Mar 8 2015, 01:12:06) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin Type "help", "copyright", "credits" or "license" for more information.
class C: pass ... c = C() c.__call__ = lambda *a: a c() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'C' object is not callable callable(c) False hasattr(c, '__call__') True
On Fri, Apr 17, 2015 at 1:45 PM, Ionel Cristian Mărieș <contact@ionelmc.ro> wrote:
Hello,
I had an issue today with the `callable` builtin because it doesn't correctly check that the object has the __call__ attribute.
Effectively what `callable(a)` does is `hasattr(type(a), '__call__')` but that's not very straightforward. A more straightforward implementation would do something like `hasattr(a, '__call__')`.
For example:
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64
bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information.
callable <built-in function callable> class A: ... @property ... def __call__(self): ... raise AttributeError('go away') ... a = A() a <__main__.A object at 0x000000000365B5C0> a.__call__ Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in __call__ AttributeError: go away callable(a) True # it should be False :(
So it boils down to this:
hasattr(a, "__call__") False hasattr(type(a), "__call__") True
My issue is that I didn't call `callable(type(a))` but just `callable(a)`. Clearly mismatching what happens when you do hasattr(a, "__call__").
To put in contrast, this is legal and clearly indicates the descriptors are being used as expected:
class B: ... @property ... def __call__(self): ... return lambda: 1 ...
b = B() b() 1
There 's some more discussing in issue 23990 <http://bugs.python.org/issue23990> where I get slightly angry, sorry.
So were is this change actually useful? Proxies! Since new-style objects in Python you cannot really proxy the callable aspect of objects, because `callable` just checks that a field is set in a C struct. This is fairly inconvenient because you have to know upfront if your target is going to be callable or not.
Thanks, -- Ionel Cristian Mărieș, http://blog.ionelmc.ro
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido)