Python Puzzle - Where Did The Time Go
Python Puzzle - Where Did The Time Go
Written by Alex Armstrong   
Article Index
Python Puzzle - Where Did The Time Go


OK - the problem is nothing to do with time keeping!

The same behavior could be demonstrated if almost any function was used to supply a default value in the same way. There are even problems if the default value is any mutable datatype, but that is another puzzle. 

The reason for the difficulty is that the function defaults are computed at the time the function is defined - not when it is called. 

So the default value for time1 is set when the Python interpreter reaches the definition of the function; not when the program calls the function.

This has two effects. The first is that the default value isn't set to the current time but the time when the function is defined. The second is that the apparent current time never changes. 

If you don't believe me try:

print( timediff(0))
print( timediff(0))
print( timediff(0))
print( timediff(0))

and you will see the same time value printed four times. 

This behavior often seems very strange to programmers familiar with other languages but most compiled languages have rules for what sorts of expressions you can use as default values and initial values.  These rules tend to come down to the simple requirement that the expression has to be fully determined at compile time. For Python compile time translates to definition time - hence the behavior. 

To be clear - the time.time() function is only called when timediff is defined i.e. when the Python interpreter reaches:

def timediff(time2,time1=time.time()):
    return time2-time1

When this happens the value of the expression i.e. the function is stored and used as the default value for time1 every time timediff is called without a specified value for time1. 

This is not a bug it is how Python 2 and 3 are supposed to behave. 


So what is the solution?

The main thing you need to be aware of is that initialization and default values aren't always determined at run time.

in this specific case you could simply revert to an earlier version of the function and avoid the use of default values:

def timediff(time2,time1):
    if time1==0:
    return time2-time1

This always works, but it isn't as convenient to use because you always have to specify a value for time1 even if it is a dummy. 

A better, and slightly more subtle, solution makes use of the default value as a flag to detect when the parameter needs dynamic initialization. 

For example a simple change to the previous version:

def timediff(time2,time1=0):
    if time1==0:
    return time2-time1

Now you can call timediff with time1 not specified and have a dynamic default value set at run time. 

Of course this depends on zero being a suitable flag for the missing argument - i.e. zero isn't going to be a valid time. More generally you can use None to indicate that a value is missing. For example:

def timediff(time2,time1=None):
    if time1is None:
    return time2-time1

You can always use None as a flag for a missing argument that needs dynamic initialization. 

The rule is:

  • always do dynamic defaults inside the function so that they are applied at run time. 

If you think that the troubles of default values are now all solved, the bad news is that there are other ways things can good wrong in what seem like very odd ways. But, as already mentioned, this is another puzzle. 



More Puzzles

Programmer Puzzle - Python Swallows A Global

Here's a teaser that poses a practical problem - one that crops up in everyday Python programming. See if you can work out the answer before looking at its solution and the pattern to follow to avoid  [ ... ]

Sharpen Your Coding Skills
Jigsaw Puzzles and The MacMahon Squares

Another puzzle featuring Joe Celko's characterful pair, Melvin Frammis, an experienced developer at International Storm Door & Software, and his junior programmer sidekick, Bugsy Cottman. This cla [ ... ]

JavaScript Puzzle - The Too Tidy Assignment

There is a rule about not optimizing code too soon. Perhaps we should add to that the rule that being too tidy is often a mistake. Here we have a JavaScript example where things go wrong because of an [ ... ]

Other Articles



RSS feed of all content
I Programmer - full contents
Copyright © 2015 All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.