[Tutor] Function assignment (was: Re: Function type?) [lexical scope]

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Thu Jun 12 15:55:08 2003


On Thu, 12 Jun 2003, Zak Arntson wrote:

> > On Wed, 11 Jun 2003, Jeff Shannon wrote:
> >
> > [warning: the following is very dynamic code; do we really want to do
> > this?  *grin*]
>
> Of course! Actually, it's good to discuss that. A lot of times we'll
> write hefty code, not realizing it isn't needed (and by "we" I mean
> "me"). After this big exercise, I may decide NOT to incorporate
> dynamically-added functions. But it's still a cool thing to know.
>
> Using your way, I concocted this class:
> ###
> import new
>
> class PyFictObject:
>     def attach(self, func, name=None):
>         setattr(self,
>                 name or func.__name__,
>                 new.instancemethod(func, self, PyFictObject))
>     def msg(self, name, message):
>         def f(self, message):
>             return message
>         self.attach(f, name)



In the msg() method,

###
    def msg(self, name, message):
        def f(self, message):
            return message
        self.attach(f, name)
###

That 'f' function that's internally defined doesn't have to take in
'message' as a parameter.  Because 'f' is being defined within a function
that already has 'message', it can just use it:


###
    def msg(self, name, message):
        def f(self):
            return message
        self.attach(f, name)
###



This is one of the major cool things about Python and other "lexically
scoped" languages; these kinds of languages provide the ability to borrow
variable values from the outside.  Since 'f' is embedding in the same
lexical block of msg, it has access access to all of the local variables
too.


Here are a few more examples of lexical scope in action:

###
>>> def prefixMaker(prefix):
...     def f(x):
...         return prefix + x
...     return f
...
>>> foo = prefixMaker('Foo!')
>>> foo('bar')
'Foo!bar'
>>> foo('tar')
'Foo!tar'
>>>
>>>
>>> def alternatingMsg(msg1, msg2):
...     state = { 'count' : 0 }
...     def f():
...         state['count'] += 1
...         if state['count'] % 2 == 0:
...             return msg1
...         else:
...             return msg2
...     return f
...
>>> flip_flop = alternatingMsg('flip', 'flop')
>>> flip_flop()
'flop'
>>> flip_flop()
'flip'
>>> flip_flop()
'flop'
>>> flip_flop()
'flip'
###


True lexical scope --- nested scope --- is one of those things that's hard
to do in a traditional language like C (although we can sorta fake it with
classes in C++).


And the second example shows something very neat:  it's a hint of the sort
of thing that's was only possible with classes before: flip_flop() is a
function that has a kind of state memory.  In fact, with a little more
work, these things start looking a lot like classes, but without the extra
syntax.


Please feel free to ask questions about it: it may be new enough to Python
programmers that it's worthwhile to delve into it.


Good luck!