Call Expressions: __call__

The __call__ method is called when your instance is called. No, this isn’t a circular definition—if defined, Python runs a __call__ method for function call expressions applied to your instances, passing along whatever positional or keyword arguments were sent:

>>> class Callee:
...     def __call__(self, *pargs, **kargs):       # Intercept instance calls
...         print('Called:', pargs, kargs)         # Accept arbitrary arguments
...
>>> C = Callee()
>>> C(1, 2, 3)                                     # C is a callable object
Called: (1, 2, 3) {}
>>> C(1, 2, 3, x=4, y=5)
Called: (1, 2, 3) {'y': 5, 'x': 4}

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

More formally, all the argument-passing modes we explored in Chapter 18 are supported by the __call__ method—whatever is passed to the instance is passed to this method, along with the usual implied instance argument. For example, the method definitions:

class C:
    def __call__(self, a, b, c=5, d=6): ...        # Normals and defaults

class C:
    def __call__(self, *pargs, **kargs): ...       # Collect arbitrary arguments

class C:
    def __call__(self, *pargs, d=6, **kargs): ...  # 3.0 keyword-only argument

all match all the following instance calls:

X = C()
X(1, 2)                                            # Omit defaults
X(1, 2, 3, 4)                                      # Positionals
X(a=1, b=2, d=4)                                   # Keywords
X(*[1, 2], **dict(c=3, d=4))                       # Unpack arbitrary arguments
X(1, *(2,), c=3, **dict(d=4))                      # Mixed modes

The net effect is that classes and instances with a __call__ support the exact same argument syntax and semantics as normal functions and methods.

Intercepting call expression like this allows class instances to emulate the look and feel of things like functions, but also retain state information for use during calls (we saw a similar example while exploring scopes in Chapter 17, but you should be more familiar with operator overloading here):

>>> class Prod:
...     def __init__(self, value):                 # Accept just one argument
...         self.value = value
...     def __call__(self, other):
...         return self.value * other
...
>>> x = Prod(2)                                    # "Remembers" 2 in state
>>> x(3)                                           # 3 (passed) * 2 (state)
6
>>> x(4)
8

In this example, the __call__ may seem a bit gratuitous at first glance. A simple method can provide similar utility:

>>> class Prod:
...     def __init__(self, value):
...         self.value = value
...     def comp(self, other):
...         return self.value * other
...
>>> x = Prod(3)
>>> x.comp(3)
9
>>> x.comp(4)
12

However, __call__ can become more useful when interfacing with APIs that expect functions—it allows us to code objects that conform to an expected function call interface, but also retain state information. In fact, it’s probably the third most commonly used operator overloading method, behind the __init__ constructor and the __str__ and __repr__ display-format alternatives.