Python: Dynamic Typing
Note: Lines beginning with ">>>"
and "..." indicate input to Python (these
are the default prompts of the interactive interpreter).
Everything else is output from Python.
|
The following example demonstrates how a function can
examine its own arguments and do different things
depending on their types. The names of the types
("IntType" etc.) are defined in a module
called "types", so we have to import them.
This kind of dynamic typing has advantages as well as disadvantages.
The advantage is clearly that it gives a lot of freedom to the
programmer and enables him to do things that wouldn't be
possible otherwise. For example, you can write functions
to which you can pass an integer as well as a string or a list
or a dictionary or whatever else, and it will be able to
transparently handle all of them in appropriate ways (or throw
an exception if it cannot handle the type). You can do things
like that in other languages, too, but usually you have to
resort to (ab)use things like pointers, references or
typecasts, which opens holes for programming errors, and
it's just plain ugly.
The obvious disadvantage of dynamic typing is that the
compiler cannot perform complete typechecks at compile-time,
therefore it is possible that bugs creep in that are hard to
find. On the other hand, Python's capabilities to handle
types and runtime-errors (exceptions) in a very natural and
convenient way prevents such problems most of the time.
Furthermore, there are several other ways to assist in
writing correct code, such as the assert statement
and the doctest module for automated regression
tests.
By the way, instead of importing the types module,
you can compare the type of a variable with the type of
a known constant. So, the above function could be rewritten
like this:
Beginning at Python 2.3, the names of built-in functions that
create values of a specific type (int, float,
str, list, tuple etc.) can be used
as types, too. So the above conditional can be simply
rewritten like this:
Here is a more complicated example. It defines a so-called
dictionary (in other languages, these are called associative
arrays or hashes). The keys of the dictionary are types,
and the values are lambda functions that handle two arguments
of that type.
By the way, you can use anything as keys in a dictionary,
even complicated structured types if you want, as long as
they are "immutable" (i.e. they cannot be changed, for
obvious reasons).
|
>>> jobs = {
... IntType: lambda x, y: x**2 + y,
... StringType: lambda x, y: y.join(x.split())
... ListType: lambda x, y: [min(x), max(x), min(y), max(y)]
... }
>>>
>>> def something(a, b):
... if type(a) != type(b):
... raise "Arguments not of the same type"
... if not jobs.has_key(type(a)):
... raise "Don't know how to handle this type"
... return jobs[type(a)](a, b)
...
>>> print something(4, 5)
>>>
>>> print something("This is so useless.", " ... ")
This ... is ... so ... useless.
|
>>>
>>> print something([5, 3, 11, 9, 7], [20, 16, 8, 24, 14, 18])
>>>
>>> print something(3, "7")
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in something
Arguments not of the same type
|
|
This is not a useful real-world example, of course, but it
demonstrates some of the possibilities. Note that Python
does not require a large amount of cryptic syntax. You
can code powerful tasks in simple, readable statements.