Newcomers to the language are sometimes surprised to find that you can pass all kinds of things as arguments to functions, and use them quite naturally inside the functions. The classic example is functions themselves. Let's write a program containing an innocuous little function that takes a function as its first argument and returns the result of calling the function on its second and third arguments.
The adder function adds two arguments, and pass that as the first argument to caller a couple of times. If all has gone to plan the first two lines of output will look like this:
def caller(f, a, b):
return f(a, b)
def adder(x, y):
print(caller(adder, "abc", "def"))
print(caller(adder, 123, 456))
def __init__(self, first, second):
self.first = first
self.second = second
obj = caller(MyCls, "=", 10)
abcdefThe first argument to adder isn't constrained to be a function. It just has to be something that can be called.We can take advantage of the fact that a call to a class creates an instance of the class to have caller create the instance for us. The MyCls class has an __init__() method that takes two arguments (as well as the ubiquitous self that the zealots will try and persuade you isn't necessary).
The call to caller returns an instance of MyCls. When that instance's method() is called it uses the remembered arguments to print out a string of ten equals signs:
The generality that this demonstrates can be difficult to get used to if you haven't come across anything like it before. Once you appreciate it, though, it gives you a flexibility that is hard to match in many other languages. That's one of the reasons why the Python world often talks about "callables": we don't care whether it's a function or a class, we only care that it can be called.
This is one aspect of polymorphism, one of the foundations of object-oriented programming.
[The code will run under Python 2, but the output shown here was produce by Python 3. The output from Python 2 will differ slightly].