why UnboundLocalError?
Bengt Richter
bokr at oz.net
Sat Jul 9 02:17:20 EDT 2005
On Fri, 8 Jul 2005 21:21:36 -0500, Alex Gittens <swiftset at gmail.com> wrote:
>I'm trying to define a function that prints fields of given widths
>with specified alignments; to do so, I wrote some helper functions
>nested inside of the print function itself. I'm getting an
>UnboundLocalError, and after reading the Naming and binding section in
>the Python docs, I don't see why.
>
>Here's the error:
>>>> fieldprint([5, 4], 'rl', ['Ae', 'Lau'])
>Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> File "fieldprint.py", line 35, in fieldprint
> str +=3D cutbits()
> File "fieldprint.py", line 11, in cutbits
> for i in range(0, len(fields)):
>UnboundLocalError: local variable 'fields' referenced before assignment
>
>This is the code:
>def fieldprint(widths,align,fields):
>
> def measure():
> totallen =3D 0
> for i in range(0, len(fields)):
> totallen +=3D len(fields[i])
> return totallen
>
> def cutbits():
> cutbit =3D []
> for i in range(0, len(fields)):
> if len(fields[i]) >=3D widths[i]:
> cutbit.append(fields[i][:widths[i]])
> fields =3D fields[widths[i]:]
fields[i] = fields[i][widths[i]:] # did you mean this, analogous to [1] below?
> elif len(fields[i]) > 0:
> leftover =3D widths[i] - len(fields[i])
> if align[i] =3D=3D 'r':
> cutbit.append(' '*leftover + fields=
>[i])
> elif align[i] =3D=3D 'l':
> cutbit.append(fields[i] + ' '*lefto=
>ver)
> else:
> raise 'Unsupported alignment option=
>'
> fields[i] =3D ''
^^^^^^^^^-- [1]
> else:
> cutbit.append(' '*widths[i])
> return cutbit.join('')
>
> if len(widths) !=3D len(fields) or len(widths)!=3Dlen(align) or
>len(align)!=3Dlen(fields):
> raise 'Argument mismatch'
>
> str =3D ''
>
>
> while measure()!=3D0:
> str +=3D cutbits()
>
>What's causing the error?
Maybe the missing [i]'s ?
It's not clear what you are trying to do with a field string that's
wider than the specified width. Do you want to keep printing lines that
have all blank fields except for where there is left-over too-wide remnants? E.g.,
if the fields were ['left','left12345','right','12345right'] and the widths were [5,5,6,6] and align 'llrr'
should the printout be (first two lines below just for ruler reference)
1234512345123456123456
LLLLLLLLLLRRRRRRRRRRRR
left left1 right12345r
2345 ight
or what? I think you can get the above with more concise code :-)
but a minor mod to yours seems to do it:
>>> def fieldprint(widths,align,fields):
... def measure():
... totallen = 0
... for i in range(0, len(fields)):
... totallen += len(fields[i])
... return totallen
... def cutbits():
... cutbit = []
... for i in range(0, len(fields)):
... if len(fields[i]) >= widths[i]:
... cutbit.append(fields[i][:widths[i]])
... #fields = fields[widths[i]:]
... fields[i] = fields[i][widths[i]:] # did you mean this, analogous to [1] below?
... elif len(fields[i]) > 0:
... leftover = widths[i] - len(fields[i])
... if align[i] == 'r':
... cutbit.append(' '*leftover + fields[i])
... elif align[i] == 'l':
... cutbit.append(fields[i] + ' '*leftover)
... else:
... raise 'Unsupported alignment option'
... fields[i] = '' # <-- [1]
... else:
... cutbit.append(' '*widths[i])
... # XXX return cutbit.join('')
... return ''.join(cutbit)
... if len(widths) != len(fields) or len(widths)!=len(align) or len(align)!=len(fields):
... raise 'Argument mismatch'
... # str = ''
... result_lines = []
... while measure()!=0:
... result_lines.append(cutbits())
... #str += cutbits()
... return '\n'.join(result_lines)
...
>>> fieldprint([5,5,6,6], 'llrr', ['left', 'left12345', 'right', '12345right'])
'left left1 right12345r\n 2345 ight'
>>> print fieldprint([5,5,6,6], 'llrr', ['left', 'left12345', 'right', '12345right'])
left left1 right12345r
2345 ight
Note that
for i in xrange(len(items)):
item = items[i]
# mess with item
just to walk through items one item at a time is more concisely written
for item in items:
# mess with item
and if you really need the index i as well,
for i, item in enumerate(items):
# use item and i here
Also, if you are going to raise 'Argument mismatch' it would be better to do it at the beginning
and use a standard exception. String exceptions are frowned upon these days, so probably raise
ValueError or TypeError with the string as an argument instead, unless you have a more informative thing to do.
BTW, measure above can be defined with current builtins as (untested)
def measure(): return sum([len(field) for field in fields])
I'll leave a few things ...
HTH
Regards,
Bengt Richter
More information about the Python-list
mailing list