Re: why UnboundLocalError?

2005-07-09 Thread Bengt Richter
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?

2005-07-09 Thread and-google
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?

2005-07-09 Thread Bengt Richter
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?

2005-07-09 Thread Bengt Richter
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?

2005-07-08 Thread Alex Gittens
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?

2005-07-08 Thread Peter Hansen
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?

2005-07-08 Thread Steven D'Aprano
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