[Tutor] design question -- nested loops considered harmful?
Danny Yoo
dyoo at hkn.eecs.berkeley.edu
Tue Nov 30 08:13:11 CET 2004
> > def pars_file(list_of_lines):
> > ####internal FunctionS###########
> > def check_flags(line,flags=item_flags,adict=data_dict):
> > for item in flags:
> > if line.startswith(item):
> > adict[item]=line[len(item)]
> > return
> > ####end internal functions####
> > ####start main function suite####
> > data_dict={}
> > for line in list_of_lines:
> > check_flags(line)
> > return data_dict
> If anyone could either explain the conventional wisdom or set straight
> my belief that distaste for nested defs is indeed widespread and well
> founded, I'd be grateful.
Hi Brian,
It's a funny thing for me: whenever I write a nested definition, I often
find that the embedded definition is often useful enough to be itself an
outer definition. *grin*
It does seem that internal definitions are mostly avoided. Part of this
might be because Python didn't have real lexical scope until the Python 2
series, but I also suspect it's just because they're just harder to test,
since they're only accessible from the scope of the surrounding function.
I hardly write inner definitions without being tempted to make them
generally useable. For the function above, for example, I can't help but
see if a general definition might work:
###
def parse_tagged_line(line):
"""A general parser for "tagged" lines of the form:
[tag_name] rest_of_line
Returns a 2-tuple (tag_name, rest_of_line).
If the line doesn't appear to be tagged, returns (None, line).
"""
regex = re.compile(r"""
\[
([^\]]*) ## The tag
\]
(.*)$ ## followed by the end of the line
""", re.VERBOSE)
if regex.match(line):
return regex.match(line).groups()
else:
return (None, line)
###
This is a generalized version of the line-parsing inner loop code, but it
tries to parse anything that looks like a tagged line. For example:
###
>>> parse_tagged_line("[email] dyoo at hkn.eecs.berkeley.edu")
('email', ' dyoo at hkn.eecs.berkeley.edu')
>>> parse_tagged_line("[Name] Brian van den Broek")
('Name', ' Brian van den Broek')
>>> parse_tagged_line("This is just a regular line")
(None, 'This is just a regular line')
###
If we have 'parsed_tagged_line()', then the parse_file() function can be
flattened down a bit, from:
###
def parse_file(list_of_lines):
data_dict = {}
for line in list_of_lines:
for item in item_flags:
if line.startswith(item):
data_dict[item] = line[len(item):]
break
return data_dict
###
to something like this:
###
def parse_file(list_of_lines):
data_dict = {}
for line in list_of_lines:
tag, rest = parse_tagged_line(line)
if tag in item_flags:
data_dict[tag] = rest
return data_dict
###
Embedded inner loops can be a ripe target for refactoring. Sometimes, the
refactoring makes absolutely no sense at all, and the inner loop is better
left alone as it is. In the example above, though, I think the extraction
can help.
More information about the Tutor
mailing list