Problem with Lexical Scope
Duncan Booth
duncan.booth at invalid.invalid
Mon Dec 12 04:00:14 EST 2005
jslowery at gmail.com wrote:
> I am using python2.4 and the following code throws a "status variable"
> not found in the inner-most function, even when I try to "global" it.
>
> def collect(fields, reducer):
> def rule(record):
> status = True
> def _(x, y):
> cstat = reducer(x, y)
> if status and not cstat:
> status = False
> return y
> return reduce(_, [record[field] for field in fields])
> return rule
>
> What gives?
You rebind status in the inner function. Binding to a name makes it local
to that function (unless declared global). A name in an enclosing function
is neither local nor global so you cannot rebind it.
Ways round this include storing the status in a mutable value, making it an
attribute of a class, or rewriting the code to not require setting an outer
variable in the first place.
The last of these is the easiest in this case: status is never actually
used or returned anywhere so you could just remove all references to it
with no impact on the code. In fact, so long as reducer has no side
effects, you could just do this:
def collect(fields, reducer):
def rule(record):
if fields:
return record[fields[-1]]
return rule
Alternatively, if I assume you actually wanted rule to return the status as
well as y, then the outer assignment disappears quite easily:
def collect(fields, reducer):
def rule(record):
def _((x, status), y):
cstat = reducer(x, y)
return (y, status and cstat)
return reduce(_, [record[field] for field in fields], (0, True))
return rule
If reducer has no side effects this can be further reduced:
def collect(fields, reducer):
def rule(record):
def _((x, status), y):
return (y, status and reducer(x,y))
return reduce(_, [record[field] for field in fields], (0, True))
return rule
Given that the final y returned is simply the last record[field] maybe you
only wanted the status value? In that case expanding the reduce and _ into
inline code is likely to make things clearer:
def collect(fields, reducer):
def rule(record):
prev = 0
for field in fields:
if not reducer(prev, record[field]):
return False
prev = record[field]
return True
return rule
More information about the Python-list
mailing list