Re: Python Mystery Theatre -- Episode 2: Así Fue
Bengt Richter
bokr at oz.net
Wed Jul 16 10:36:19 EDT 2003
On Tue, 15 Jul 2003 10:54:15 +0200, "Helmut Jarausch" <jarausch at igpm.rwth-aachen.de> wrote:
>Fredrik Lundh wrote:
>> Helmut Jarausch wrote:
>>
>>
>>>OK, I believe to know why the last line
>>>print '3' three times, since only a reference
>>>to 'f' is stored within the lambda expression
>>>and this has the value 'thrice' when 'print'
>>>is executed.
>>>
>>>But how can I achieve something like an
>>>evaluation of one indirection so that
>>>a reference to the function referenced by 'f'
>>>is stored instead.
>>
>>
>> assuming you meant "the function reference by 'f' when the lambda
>> is created", the easiest solution is to use default argument binding:
>>
>> flam = [lambda x,f=f: f(x) for f in funcs]
>>
>> the "f=f" construct will bind the inner name "f" to the current value of
>> the outer "f" for each lambda.
>>
>> the nested scopes mechanism is often introduced as the "right way" to
>> do what was done with argument binding in earlier versions of Python.
>> however, nested scopes bind *names*, while argument binding binds
>> *values*.
>
>Many thanks for that hint,
>still a part of the question remains (unclear to me)
>
>Obviously Python allows references to references, since
>e.g. 'once' (the 'name' of a function) is a reference to
>the code and 'f' is a reference to that reference. (you call it
>name binding)
>A similar situation arises in Maple and there one has the choice
>to either derefence all references down to the real object
>or to just derefence a single time.
>
>Example
>
>def once(x): return x
>def twice(x): return 2*x
>ref= once
>def caller():
> callee=ref # (*)
> print callee(1)
>
>caller() # prints 1
>ref= twice
>caller() # prints 2 so that demonstrates name binding
>
>how can I get the current value (like 'xdef' in TeX)
>of 'ref' in the assignment (*) above, so that
>'callee' becomes an (immutable) reference to 'once' ?
>
IWT the straight-forward way would be to capture ref in a callable class instance:
>>> def once(x): return x
...
>>> def twice(x): return 2*x
...
>>> class Caller(object):
... def __init__(self): self.callee = ref # global ref at time of init
... def __call__(self): print self.callee(1)
...
>>> ref = once
>>> caller = Caller()
>>> caller()
1
>>> ref = twice
>>> caller()
1
>>> caller2 = Caller()
>>> caller2()
2
>>> caller()
1
You could also make a factory function that captures ref using a closure:
>>> def ffun():
... callee = ref
... def caller(): print callee(1)
... return caller
...
>>> ref = once
>>> caller = ffun()
>>> caller()
1
>>> ref = twice
>>> caller_twice = ffun()
>>> caller_twice()
2
If you just wanted the first-used ref to be "sticky," you could do something kludgy:
(note that this pospones capturing ref until the first call vs class instance creation or ffun call)
>>> def caller():
... if not hasattr(caller,'callee'): setattr(caller,'callee',ref)
... print caller.callee(1)
...
>>> ref = once
>>> caller()
1
>>> ref = twice
>>> caller()
1
You can "unstick" it and have it stick again:
>>> del caller.callee
>>> caller()
2
>>> ref = once
>>> caller()
2
Regards,
Bengt Richter
More information about the Python-list
mailing list