
本文详解 Python 中 Class(args1)(args2) 这一常见模式——它并非语法糖,而是基于 __call__ 协议的可调用对象链式调用,广泛用于 Keras 等函数式 API 中。
本文详解 python 中 `class(args1)(args2)` 这一常见模式——它并非语法糖,而是基于 `__call__` 协议的可调用对象链式调用,广泛用于 keras 等函数式 api 中。
在 TensorFlow/Keras 的函数式 API 中,你常会见到类似这样的代码:
x = layers.Dense(128 * 16 * 16)(inputs)
表面上看,这像“构造器后紧跟一对括号”,容易误以为是某种特殊语法。但实际上,这是 两次独立的函数调用,由 Python 的可调用对象(callable)机制自然支持。
? 核心原理:__call__ 协议
Python 中,任何实现了 __call__ 方法的对象都是可调用的(即能用 obj(...) 语法)。layers.Dense 是一个类,其构造函数 Dense(units) 返回的不是普通实例,而是一个可调用层对象(即实现了 __call__ 的类实例):
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
# 第一次调用:实例化 Dense 层(配置参数) dense_layer = layers.Dense(2048) # 返回一个 callable 对象 # 第二次调用:将输入张量传入该层执行前向计算 output = dense_layer(inputs) # 实际调用 dense_layer.__call__(inputs)
等价于一行写法:
立即学习“Python免费学习笔记(深入)”;
output = layers.Dense(2048)(inputs) # 构造 + 调用,链式表达
✅ 可调用对象示例(自定义实现)
你可以轻松模拟这一行为:
class Adder:
def __init__(self, offset):
self.offset = offset
def __call__(self, x):
return x + self.offset
# 使用方式完全一致
add_5 = Adder(5)
result = add_5(10) # → 15
print(Adder(3)(7)) # → 10(双括号链式调用)⚠️ 注意事项与最佳实践
-
不是所有类都支持双括号:只有显式实现
__call__的类(或返回 callable 的工厂函数)才适用; -
Keras 层的设计意图:
Dense(...)是层配置阶段(声明性),(inputs)是连接/执行阶段(图构建),二者分离提升了模型可组合性; -
调试建议:若遇到
TypeError: 'xxx' object is not callable,说明中间对象未实现__call__,需检查返回值类型; -
性能无额外开销:两次调用均为普通方法分发,
__call__与普通方法调用性能一致。
? 总结
layers.Dense(128)(inputs) 是 Python 可调用协议的典型应用:
✅ 第一重括号 Dense(128) —— 初始化并返回一个 callable 层对象;
✅ 第二重括号 (inputs) —— 触发该对象的 __call__ 方法,完成张量运算。
这种设计让 Keras 函数式 API 同时兼具面向对象的配置能力与函数式编程的简洁表达力,是深度学习框架中“声明即构建”范式的基石。

















