Where do nested functions live?

Frederic Rentsch anthra.norell at vtxmail.ch
Sun Oct 29 04:16:45 EST 2006


Diez B. Roggisch wrote:
>> If I may turn the issue around, I could see a need for an inner function 
>> to be able to access the variables of the outer function, the same way a 
>> function can access globals. Why? Because inner functions serve to 
>> de-multiply code segments one would otherwise need to repeat or to 
>> provide a code segment with a name suggestive of its function. In either 
>> case the code segment moved to the inner function loses contact with its 
>> environment, which rather mitigates its benefit.
>>     
>
> Maybe I'm dense here, but where is your point? Python has nested lexical 
> scoping, and while some people complain about it's actual semantics, it 
> works very well:
>
> def outer():
>     outer_var = 10
>     def inner():
>         return outer_var * 20
>     return inner
>
> print outer()()
>
>
>
> Diez
>   
My point is that an inner function operating on existing outer variables 
should be allowed to do so directly. Your example in its simplicity is 
unproblematic. Let us consider a case where several outer variables need 
to be changed:

   weeks = days = hours = minutes = seconds = 0
   mseconds = 0.0

   (code)

   # add interval in milliseconds
   have_ms = ((((((((((weeks * 7) + days) * 24) + hours) * 60) + 
minutes) * 60) + seconds) * 1000) + mseconds)
   new_ms = have_ms + interval_ms
   # reconvert
   s = new_ms / 1000.0
   s = int (s)
   mseconds = new_ms - s * 1000
   m, seconds = divmod (s, 60)
   h, minutes = divmod (m, 60)
   d, hours = divmod (h, 24)
   weeks, days = divmod (d, 7)

   (more code)

At some later point I need to increment my units some more and probably 
will again a number of times. Clearly this has to go into a function. I 
make it an inner function, because the scope of its service happens to 
be local to the function in which it comes to live. It operates on 
existing variables of what is now its containing function.

   def increment_time (interval_ms):
      have_ms = ((((((((((weeks * 7) + days) * 24) + hours) * 60) + 
minutes) * 60) + seconds) * 1000) + mseconds)
      new_ms = have_ms + interval_ms
      # reconvert
      s = new_ms / 1000.0
      s = int (s)
      ms -= s * 1000       # Was mseconds = new_ms - s * 1000
      m, s = divmod (s, 60)    # Was m, seconds = divmod (s, 60)
      h, m = divmod (m, 60)    # Was h, minutes = divmod (m, 60)
      d, h = divmod (h, 24)    # Was d, hours = divmod (h, 24)
      w, d = divmod (d, 7)     # Was weeks, days = divmod (d, 7)
      return w, d, h, m, s, ms

Functionizing I must change the names of the outer variables. Assigning 
to them would make them local, their outer namesakes would become 
invisible and I'd have to pass them all as arguments. Simpler is 
changing assignees names, retaining visibility and therefore not having 
to pass arguments. In either case I have to return the result for 
reassignment by the call.

   weeks, days, hours, minutes, seconds, milliseconds = increment_time 
(msec)

This is a little like a shop where the mechanics have to get their tools 
and work pieces from the manager and hand them back to him when they're 
done. The following two examples are illustrations of my point. They are 
not proposals for 'improvement' of a language I would not presume to 
improve. 

   def increment_time (interval_ms):
      outer weeks, days, hours, minutes, seconds, mseconds   # 'outer' 
akin to 'global'
      (...)
      mseconds = new_ms - s * 1000        # Assignee remains outer
      m, seconds = divmod (s, 60)
      h, minutes = divmod (m, 60)
      d, hours = divmod (h, 24)
      weeks, days = divmod (d, 7)         # No return necessary

The call would now be:

   increment_time (msec)                  # No reassignment necessary


Hope this makes sense

Frederic





More information about the Python-list mailing list