12.3 A First Example: Definitions and Calls
Apart from such
runtime
concepts (which tend to seem most unique to programmers with
backgrounds in traditional compiled languages), Python functions are
straightforward to use. Let's code a first real
example to demonstrate the basics. Really, there are two sides to the
function picture: a definition—the
def that creates a function, and a
call—an expression that tells Python to
run the function's body.
12.3.1 Definition
Here's a definition typed interactively that defines
a function called times, which returns the product
of its two arguments:
>>> def times(x, y): # Create and assign function.
... return x * y # Body executed when called.
...
When Python reaches and runs this def, it creates
a new function object that packages the function's
code, and assign the object to the name times.
Typically, this statement is coded in a module file, and it would run
when the enclosing file is imported; for something this small,
though, the interactive prompt suffices.
12.3.2 Calls
After the def has run, the program can call (run)
the function by adding parentheses after the
function's name; the parentheses may optionally
contain one or more object arguments, to be passed (assigned) to the
names in the function's header:
>>> times(2, 4) # Arguments in parentheses
8
This expression passes two arguments to times: the
name x in the function header is assigned the
value 2, y is assigned
4, and the function's body is
run. In this case, the body is just a return
statement, which sends back the result as the value of the call
expression. The returned object is printed here interactively (as in
most languages, 2*4 is 8 in
Python); it could also be assigned to a variable if we need to use it
later:
>>> x = times(3.14, 4) # Save the result object.
>>> x
12.56
Now, watch what happens when the function is called a third time,
with very different kinds of objects passed in:
>>> times('Ni', 4) # Functions are "typeless."
'NiNiNiNi'
In this third call, a string and an integer are passed to
x and y, instead of two
numbers. Recall that * works on both numbers and
sequences; because you never declare the types of variables,
arguments, or return values, you can use times to
multiply numbers or repeat
sequences.
12.3.3 Polymorphism in Python
In fact, the very meaning of the expression x * y
in the simple times function depends completely
upon the kinds of objects that x and
y are—it means multiplication first and
repetition second. Python leaves it up to the
objects to do something reasonable for this
syntax.
This sort of type-dependent behavior is known as
polymorphism—which
means that the meaning of operations depends on the objects being
operated upon. Because Python is a dynamically typed language,
polymorphism runs rampant: every operation is a polymorphic operation
in Python.
This is a deliberate thing, and accounts for much of the
language's flexibility. A single function, for
instance, can generally be applied to a whole categoy of object
types. As long as those objects support the expected
interface (a.k.a. protocol), they can be
processed by the function. That is, if the objects passed in to a
function have the expected methods and operators, they are
plug-and-play compatible with the function's logic.
Even in our simple times function, this means that
any two objects that support a
* will work, no matter what they may be, and no
matter when they may be coded. Moreover, if the objects passed in do
not support this expected interface, Python will
detect the error when the * expression is run, and
raise an exception automatically. It's pointless to
code error checking ourselves here.
This turns out to be a crucial philosophical difference between
Python and statically typed languages like C++ and Java: in Python,
your code is not supposed to care about specific
data types. If it does, it will be limited to work on just the types
you anticipated when you wrote your code. It will not support other
compatible object types coded in the future. Although it is possible
to test for types with tools like the type
built-in function, doing so breaks your code's
flexibility. By and large, we code to object
interfaces in Python, not data types.
|