Re: why UnboundLocalError?
On Fri, 8 Jul 2005 21:21:36 -0500, Alex Gittens [EMAIL PROTECTED] 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 LL 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
Re: why UnboundLocalError?
Alex Gittens wrote: I'm getting an UnboundLocalError def fieldprint(widths,align,fields): [...] def cutbits(): [...] fields = fields[widths[i]:] There's your problem. You are assigning 'fields' a completely new value. Python doesn't allow you to rebind a variable from an outer scope in an inner scope (except for the special case where you explicitly use the 'global' directive, which is no use for the nested scopes you are using here). So when you assign an identifier in a function Python assumes that you want that identifier to be a completely new local variable, *not* a reference to the variable in the outer scope. By writing 'fields= ...' in cutbits you are telling Python that fields is now a local variable to cutbits. So when the function is entered, fields is a new variable with no value yet, and when you first try to read it without writing to it first you'll get an error. What you probably want to do is keep 'fields' pointing to the same list, but just change the contents of the list. So replace the assign operation with a slicing one: del fields[:widths[i]] -- Andrew Clover mailto:[EMAIL PROTECTED] http://www.doxdesk.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: why UnboundLocalError?
On 9 Jul 2005 05:26:46 -0700, [EMAIL PROTECTED] wrote: Alex Gittens wrote: I'm getting an UnboundLocalError def fieldprint(widths,align,fields): [...] def cutbits(): [...] fields = fields[widths[i]:] There's your problem. You are assigning 'fields' a completely new value. Python doesn't allow you to rebind a variable from an outer scope in an inner scope (except for the special case where you explicitly use the 'global' directive, which is no use for the nested scopes you are using here). So when you assign an identifier in a function Python assumes that you want that identifier to be a completely new local variable, *not* a reference to the variable in the outer scope. By writing 'fields= ...' in cutbits you are telling Python that fields is now a local variable to cutbits. So when the function is entered, fields is a new variable with no value yet, and when you first try to read it without writing to it first you'll get an error. What you probably want to do is keep 'fields' pointing to the same list, but just change the contents of the list. So replace the assign operation with a slicing one: del fields[:widths[i]] Except the OP probably had two errors in that line, and doesn't want to slice out fields from the field list, but rather slice characters from the i-th field, and strings are immutable, so he can't do del fields[i][:widths[i]] # slice deletion illegal if fields[i] is a string and so fields[i] = fields[i][:widths[i]] would be the way to go (see my other post). Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list
Re: why UnboundLocalError?
On Sat, 09 Jul 2005 06:17:20 GMT, [EMAIL PROTECTED] (Bengt Richter) wrote: On Fri, 8 Jul 2005 21:21:36 -0500, Alex Gittens [EMAIL PROTECTED] 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. 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 LL 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: [...] Not very tested, but you may enjoy puzzling out a more concise version (and writing a proper test for it, since it might have bugs ;-) def fieldprint(widths, align, fields): ... if len(widths) != len(fields) or len(widths)!=len(align): ... raise ValueError, 'fieldprint argument mismatch' ... align = [getattr(str, j+'just') for j in align] ... results = [] ... while ''.join(fields): ... for i, (fld, wid, alg) in enumerate(zip(fields, widths, align)): ... results.append(alg(fld[:wid], wid)) ... fields[i] = fld[wid:] ... results.append('\n') ... return ''.join(results) ... print fieldprint([5,5,6,6], 'llrr', ['left', 'left12345', 'right', '12345right']) left left1 right12345r 2345 ight BTW, since this destroys the fields list, you might want to operate on a copy (e.g., remaining_fields = fields[:]) internally, or pass a copy to the routine. Of course, you could put print instead of return in fieldprint and just call it instead of printing what it returns as above, but you didn't show that part in your original example. BTW2, note that str above is the built in string type, and it's not a good idea to use a built in name for a variable the way your original code did. Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list
why UnboundLocalError?
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 += 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 = 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]:] 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] = '' else: cutbit.append(' '*widths[i]) return cutbit.join('') if len(widths) != len(fields) or len(widths)!=len(align) or len(align)!=len(fields): raise 'Argument mismatch' str = '' while measure()!=0: str += cutbits() What's causing the error? Thanks, Alex -- ChapterZero: http://tangentspace.net/cz/ -- http://mail.python.org/mailman/listinfo/python-list
Re: why UnboundLocalError?
Alex Gittens 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 += 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): [snip] 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]:] What's causing the error? While I don't know the correct fix, the immediate cause is that you are assigning to fields in the final line above, and there is no global fields statement, so the compiler thinks it must be a local, but you access it (as the error says) before it is assigned-to locally. A fix would be to use a different name locally, and if you really want it to reference the externally defined fields, just do something like lfields = fields at the top of cutbits() (where lfields means local fields, though you can pick any name you like). -Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: why UnboundLocalError?
On Fri, 08 Jul 2005 21:21:36 -0500, Alex Gittens wrote: str = '' while measure()!=0: str += cutbits() It is considered poor practice to use the names of built-ins like str or list as variable names. What's causing the error? Did you actually copy all of the code? It seems to me that once your code has assembled the string, it doesn't actually do anything with it. Not even return it. Also, you seem to be calling a join method on lists. Lists don't have join methods. The rest of your code is very hard for me to follow, especially as you have not put any comments in and seem to spend a lot of time re-inventing the wheel. I would do something like this to handle fixed-width printing. (Untested.) def fieldprint(widths,alignments,fields): Given a list of widths, alignments and fields (text) representing a single row of text formatted in columns, returns an aligned version. Text is never truncated to fit, and is padded with spaces. Examples: fieldprint([5, 5, 5], lcr, [cat, 12345, 12345]) = cat 1234512345 fieldprint([5, 5, 5], rcl, [cat, dog, 12345]) = cat dog 12345 fieldprint([5, 5, 5], rcl, [cat, dog, mice]) = cat dog mice # helper function def align(width, alignment, text): Give a width, an alignment, and some text, returns a string containing that text aligned correctly in columns. if alignment in Ll: # left-justify return text.ljust(width) elif alignment in Rr: # right-justify return text.rjust(width) elif alignment in Cc: # centered return text.center(width) else: raise ValueError(Unsupported alignment '%s' % alignment) if not len(widths) == len(alignments) == len(fields): raise 'Argument mismatch' columns = zip(widths, alignments, fields) # builds a list of tuple of (width, alignment, field) L = [] # hold each formatted column as it is built for column in columns: L.append(align(*column)) # equivalent to: # L.append(align(column[0], column[1], column[2])) return ''.join(L) Hope this is helpful to you. -- Steven. -- http://mail.python.org/mailman/listinfo/python-list