Re: why UnboundLocalError?
Available news archives: comp.lang.tcl - comp.lang.python - comp.security.firewalls - sci.crypt - comp.lang.php - comp.lang.javascript
Google
 
Web news.hping.org


comp.lang.python archive

Re: why UnboundLocalError?

From: Bengt Richter <bokr@oz.net>
Date: Sat Jul 09 2005 - 08:17:20 CEST

On Fri, 8 Jul 2005 21:21:36 -0500, Alex Gittens <swiftset@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
Received on Thu Sep 29 16:50:45 2005