1

I get the following output when I run the code below:

31.688087814
131.569532877

This output is produced by the two lines I have marked out below. The values should be identical(as far as I can see), and should both have the first value. I can't figure out where the value is being changed into the second value. This is an exercise from the site exercism.io. I am doing it for my own 'entertainment'. But this has me stumped. Any assistance much appreciated.

#!/usr/bin/env python

"""
Earth:   orbital period 365.25 Earth days, or 31557600 seconds
Mercury: orbital period 0.2408467 Earth years
Venus:   orbital period 0.61519726 Earth years
Mars:    orbital period 1.8808158 Earth years
Jupiter: orbital period 11.862615 Earth years
Saturn:  orbital period 29.447498 Earth years
Uranus:  orbital period 84.016846 Earth years
Neptune: orbital period 164.79132 Earth years
"""

PLANETS = {
    "on_earth": 31557600.0,
    "on_mercury": 31557600.0 * 0.2408467,
    "on_venus": 31557600.0 * 0.61519726,
    "on_mars": 31557600.0 * 1.8808158,
    "on_jupiter": 31557600.0 * 11.862615,
    "on_saturn": 31557600.0 * 29.447498,
    "on_uranus": 31557600.0 * 84.016846,
    "on_neptune": 31557600.0 * 164.79132
}

class SpaceAge(object):

    def __init__(self, seconds):
        self.seconds = seconds

        if not isinstance(seconds, (int, long, float)):
            raise ValueError("Invalid input type {}".format(type(seconds)))

        for k, v in PLANETS.iteritems():
            func = lambda : seconds / v
            if k == "on_earth":
                print func()                # <<*** first output value 
            setattr(self, k, func)

if __name__ == "__main__":
    age = SpaceAge(1e9)
    print age.on_earth()                    # <<*** second output value
Totem
  • 7,189
  • 5
  • 39
  • 66
  • 3
    `v` is a closure; it is not stored in the `lambda` but instead looked up *when you call the `lambda`*. At that point `v` is bound the last value in your `PLANETS.iteritems()` sequence. – Martijn Pieters Sep 29 '14 at 14:01
  • 1
    Replace to : `func = lambda seconds=seconds, v=v: seconds / v` – mdurant Sep 29 '14 at 14:29
  • @mdurant Excellent thank you! Does this work because seconds and v are effectively being defined locally? – Totem Sep 29 '14 at 14:51
  • That's exactly it - instead of doing a look-up on the variables at execution time, local versions are defined (note that it might be more reasonable to give them different names to avoid confusion). – mdurant Sep 29 '14 at 14:55

0 Answers0