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