How do Python tell “this is called as a function”? -
a callable object supposed defining __call__. class supposed object… or @ least exceptions. exception i'm failing formally clarify, question posted here.
let a simple class:
class a(object): def call(*args): return "in `call`" def __call__(*args): return "in `__call__`" the first function purposely named “call”, make clear purpose comparison other.
let's instantiate , forget expression implies:
a = a() # think of `a = magic` , forget `a()` now what's worth:
print(a.call()) print(a.call()) print(a()) print(a()) result in:
>>> in `call` >>> in `call` >>> <__main__.a object @ 0xnnnnnnnn> >>> in `__call__` the output (third statement not running __call__) not come surprise, when think every said “python class objects”…
this, more explicit, run __call__
print(a.__call__()) print(a.__call__()) >>> “in `__call__`” >>> “in `__call__`” all of show how a() may looks strange.
there exception in python rules, the documentation “object.call” not lot __call__… not more that:
3.3.5. emulating callable objects
object.__call__(self[, args...])called when instance “called” function; […]
but how python tell “it's called function” , honour or not object.__call__ rule?
this matter of type, type has object base class.
where can learn more (and formally) it?
by way, there difference here between python 2 , python 3?
----- %< ----- edit ----- >% -----
conclusions , other experiments after 1 answer , 1 comment
update #1
after @veedrac's answer , @chepner's comment, came other test, complete comments both:
class m(type): def __call__(*args): return "in `m.__call__`" class a(object, metaclass=m): def call(*args): return "in `call`" def __call__(*args): return "in `a.__call__`" print(a()) the result is:
>>> in `m.__call__` so seems that's meta‑class drives “call” operations. if understand correctly, meta‑class not matter class, classes instances.
update #2
another relevant test, shows not attribute of object matters, attribute of type of object:
class a(object): def __call__(*args): return "in `a.__call__`" def call2(*args): return "in `call2`" = a() print(a()) as expected, prints:
>>> in `a.__call__` now this:
a.__call__ = call2 print(a()) it prints:
>>> in `a.__call__` the same before attribute assigned. not print in call2, it's still in a.__call__. that's important note , explain why that's __call__ of meta‑class invoked (keep in mind meta‑class type of class object). __call__ used call function, not object, it's type.
x(*args, **kwargs) same type(x).__call__(x, *args, **kwargs).
so have
>>> type(a).__call__(a) <__main__.a object @ 0x7f4d88245b50> and makes sense.
chepner points out in comments type(a) == type. kind-of wierd, because type(a)(a) gives type again! remember we're instead using type(a).__call__(a) not same.
so resolves type.__call__(a). constructor function classes, builds data-structures , construction magic.
the same true of dunder (double underscore) methods, such __eq__. partially optimisation in cases.
Comments
Post a Comment