Callable objects in python - Sun, Dec 4, 2022
Callable objects in python
While doing a specialization for AI and machine learning I stumbled about the following code fragment which was part of a method which built the model (The whole source code of the method can be found here ):
# Flatten the output layer to 1 dimension
x = layers.Flatten()(last_output)
# Add a fully connected layer with 1,024 hidden units and ReLU activation
x = layers.Dense(1024, activation='relu')(x)
The syntax that I didn’t quiet understand was the closing parenthesis immediately followed by opening parenthesis )(x)
. That the code did is add the Flatten-Layer (x) to the Dense Layer directly after the constructor. After doing some research I discovered that code like this could be achieved by returning a method as outlined in the example below:
def my_function(x=1):
def inner_function(y):
return x + y
return inner_function
if __name__ == '__main__':
print(closure_function()(2)) # Should print 3
print(closure_function(2)(2)) # Should print 4
The second parenthesis would be invocation of the returned function. But since constructors may not return anything, that wasn’t the explanation. After some more research If read about callable class instances
in python. In short: classes implementing the __call__()
method cane be used like functions, as the code below illustrates:
class CallableClass:
def __init__(self, x=1):
self.x = x
def __call__(self, y):
return self.x + y
if __name__ == '__main__':
print(CallableClass()(2)) # Should print 3
print(CallableClass(2)(2)) # Should print 4
The __call()__
method can thus be invoked directly after the invocation of the class’ constructor. And indeed that was the case for the Dense
class. After having solved that mystery I wondered whether code like that is actually good code. What the invocation of the __call()__
method does in statements like this layers.Dense(1024, activation='relu')(x)
is not clear. So in order for a notation like this to be easily understandable, the name of the class should be more expressive. For example ono_and_one_is_two = AddOperation(1)(1)
.