__call__
?是一個特殊方法(也稱為魔術方法),用于使一個類的實例能夠像函數一樣被調用。當定義了這個方法后,實例對象可以后接括號(即?()
)來觸發調用,這會讓實例表現得像函數一樣。
- ?使實例可調用?:允許類的實例像函數一樣被調用。
- ?保持狀態?:可以在多次調用之間保持實例的狀態(因為實例可以存儲屬性)。
- ?實現裝飾器?:常用于實現裝飾器類(Decorator Class)。
- ?模擬函數行為?:讓對象具備函數的行為,同時保留類的特性(如屬性、方法)。
?基本語法?
class MyClass:def __call__(self, *args, **kwargs):# 定義調用時的行為return "Called with:", args, kwargsobj = MyClass()
result = obj(1, 2, 3, name="Alice") # 觸發 __call__
# result = obj() # 觸發 __call__
print(result)# ('Called with:', (1, 2, 3), {'name': 'Alice'})
# ('Called with:', (), {})
?輸出:??
('Called with:', (1, 2, 3), {'name': 'Alice'})
?關鍵特點?
-
?**
*args
?和?**kwargs
**?
__call__
?可以接受任意數量的位置參數和關鍵字參數,類似于普通函數。 -
?實例本身仍然是一個對象?
即使定義了?__call__
,實例仍然可以擁有屬性和方法:class Adder:def __init__(self, initial=0):self.total = initialdef __call__(self, x):self.total += xreturn self.totaladd = Adder(10) print(add(5)) # 15(10 + 5) print(add(3)) # 18(15 + 3)
-
?用于裝飾器?
__call__
?可以讓類的實例作為裝飾器使用:class Logger:def __init__(self, func):self.func = funcdef __call__(self, *args, ?**kwargs):print(f"Calling {self.func.__name__}")return self.func(*args, ?**kwargs)@Logger def greet(name):return f"Hello, {name}!"print(greet("Alice"))
?輸出:??
Calling greet Hello, Alice!
?**__call__
?vs?__init__
**?
方法 | 調用時機 | 用途 |
---|---|---|
__init__ | 實例化時調用(obj = MyClass() ) | 初始化對象屬性 |
__call__ | 實例被調用時(obj() ) | 讓實例像函數一樣執行 |
?實際應用場景?
-
?狀態保持的函數?(類似閉包)
class Counter:def __init__(self):self.count = 0def __call__(self):self.count += 1return self.countcounter = Counter() print(counter()) # 1 print(counter()) # 2
-
?實現策略模式?
class Multiply:def __call__(self, a, b):return a * bclass Add:def __call__(self, a, b):return a + bdef calculate(operation, a, b):return operation(a, b)print(calculate(Multiply(), 3, 4)) # 12 print(calculate(Add(), 3, 4)) # 7
-
?動態生成對象行為?
class Power:def __init__(self, exponent):self.exponent = exponentdef __call__(self, x):return x ?**? self.exponentsquare = Power(2) cube = Power(3) print(square(4)) # 16 print(cube(3)) # 27
?總結?
__call__
?讓類的實例可以像函數一樣被調用。- 適用于需要保持狀態的函數、裝飾器類、策略模式等場景。
- 不同于?
__init__
,它控制的是實例的調用行為,而非初始化行為。
如果你想讓一個對象既能存儲數據又能像函數一樣執行操作,__call__
?是一個非常有用的工具!