[Python-ideas] For-loop variable scope: simultaneous possession and ingestion of cake
Carl Johnson
carl at carlsensei.com
Mon Oct 6 04:43:22 CEST 2008
Why does the evil default args hack work? Because it immediately
evaluates the argument and stores the result into the lambda object's
default values list. So, what we need is a keyword that means
"immediately evaluate the argument and store the result, instead of
looking up the name again later." Since I can't think of a good name
for this, I will use a terrible name for it, "immanentize."
>>> i = 1
>>> def f():
... return immanentize i
...
>>> i = 2
>>> f()
1
>>> lst = []
>>> for i in range(10):
... lst.append(lambda: immanentize i)
...
>>> [f() for f in _]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> def side_effect_maker():
... print("blah")
... return datetime.datetime.now()
...
>>> def f():
... creation_time = immanentize side_effect_maker()
... return datetime.datetime.now() - creation_time
...
"blah"
>>> f() #Assume it takes you 5 seconds to type "f()" and press enter
datetime.timedelta(0, 5, 0)
Etc. Behind the scenes, this would look like syntatic sugar for
something like creating a new variable name, evaluating the expression
at initial compile time, setting the variable name to be the result of
the evaluation, and replacing the immanentize expression with the
variable name. Like this:
>>> lst = []
>>> for i in range(10):
... random_variable_name_0..9 = i
... # ie. on the first loop around random_variable_name_0 = 0, on
the second loop random_variable_name_1 = 1, etc.
... lst.append(lambda: random_variable_name_0..9)
... # ie. the first loop is evaluated as
lst.append(lambda(random_variable_name_0)), etc.
...
>>> [f() for f in _]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> def side_effect_maker():
... print("blah")
... return datetime.datetime.now()
...
>>> random_variable_name_number_0 = side_effect_maker()
"blah"
>>> def f():
... creation_time = random_variable_name_number_0
... return datetime.datetime.now() - creation_time
I think this proposal is better than using "local:" or "scope:"
because it doesn't create nested blocks when you just want to freeze
out one particular value.
One interesting side effect of having an immanentize keyword is that
in Python 4000, we could (if we wanted to) get rid of the supposed
"wart" of having x=[] as a default arg leading to unexpected results
for Python newbies. Just make it so that to get the current behavior
you type
>>> def f(x=immanentize []):
... x.append(1)
... return x
...
>>> f()
[1]
>>> f()
[1, 1]
Whereas, without immanentize we can do what newbies expect and
evaluate the defaults afresh each time.
>>> def f(x=[]):
... x.append(1)
... return x
...
>>> f()
[1]
>>> f()
[1]
Obviously, "immanentize" is a terrible name, and only just barely a
word of English. Perhaps we could call it an "anonymous variable"
instead?
-- Carl
More information about the Python-ideas
mailing list