同步阅读进度,多语言翻译,过滤屏幕蓝光,评论分享,更多完整功能,更好读书体验,试试 阅读 ‧ 电子书库
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}
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.
请支持我们,让我们可以支付服务器费用。
使用微信支付打赏