variable assignment within a loop

H

hokieghal99

I have this for loop in a program that I'm writing:

for bad_dir_char in bad_dir_chars:
newdir = dir.replace(bad_dir_char,'-')

Now, when I use this if statement:

if newdir != dir:
old_dir_path = os.path.join(root,dir)
new_dir_path = os.path.join(root,newdir)
os.rename(old_dir_path,new_dir_path)
print "replaced: ",bad_dir_char,"

I get a "local variable 'newdir' referenced before assignment" error.

I am somewhat new to programming and I do not understand a lot about
where variables live and where they do not. I know the difference
between global and function specific variables, but I was under the
impression that if a local variable lived within a function that I could
access its contents *anywhere* in that function. This is obviuously
wrong, could someone expound upon this? Not that it matters, but below
is the entire function that I'm playing with. I have a working version
of it, but I'm cleaning it up a bit (I know that that is a bad thing,
but it helps me learn more about programming).

import os, re, string
print
setpath = raw_input("Path to the Directory to act on: ")
def clean_names(setpath):
bad = re.compile(r'%2f|%25|%20|[*?<>/\|\\]') # bad characters
for root, dirs, files in os.walk(setpath):
for dir in dirs:
bad_dir_chars = bad.findall(dir)
for bad_dir_char in bad_dir_chars:
newdir = dir.replace(bad_dir_char,'-')
if newdir != dir:
old_dir_path = os.path.join(root,dir)
new_dir_path = os.path.join(root,newdir)
os.rename(old_dir_path,new_dir_path)
print "replaced: ",bad_dir_char," in dir ",dir," ",
 
D

Dave Kuhlman

hokieghal99 said:
I have this for loop in a program that I'm writing:

for bad_dir_char in bad_dir_chars:
newdir = dir.replace(bad_dir_char,'-')

Now, when I use this if statement:

if newdir != dir:
old_dir_path = os.path.join(root,dir)
new_dir_path = os.path.join(root,newdir)
os.rename(old_dir_path,new_dir_path)
print "replaced: ",bad_dir_char,"

I get a "local variable 'newdir' referenced before assignment"
error.

Assigning a value to a new variable creates the variable.

If the body of your loop is executed zero times, then newdir will
not be assigned a value, and the variable newdir will not exist.

In general, if a variable is created and initialized in a loop, it
is a good idea to initialize the variable *before* the loop.

Something like the following might work for you:

newdir = dir
for bad_dir_char in bad_dir_chars:
newdir = newdir.replace(bad_dir_char,'-')

You can find a little additional information about variables in
Python in the Python Programming FAQ, "2.2 What are the rules
for local and global variables in Python?":

http://www.python.org/doc/faq/progr...ules-for-local-and-global-variables-in-python

Note also that there are other ways to solve your problem.
Consider the following:
'/abc/e-f/g--'


See the string module for information on maketrans() and
translate.

http://www.python.org/doc/current/lib/module-string.html

[snip]

Dave
 
M

Michael Surette

I have this for loop in a program that I'm writing:

for bad_dir_char in bad_dir_chars:
newdir = dir.replace(bad_dir_char,'-')

Now, when I use this if statement:

if newdir != dir:
old_dir_path = os.path.join(root,dir)
new_dir_path = os.path.join(root,newdir)
os.rename(old_dir_path,new_dir_path)
print "replaced: ",bad_dir_char,"

I get a "local variable 'newdir' referenced before assignment" error.

This has nothing to do with where variables live. What is happening is
when bad_dir_chars is empty, newdir doesn't get assigned in your for loop.
 
J

John Roth

hokieghal99 said:
I have this for loop in a program that I'm writing:

for bad_dir_char in bad_dir_chars:
newdir = dir.replace(bad_dir_char,'-')

Now, when I use this if statement:

if newdir != dir:
old_dir_path = os.path.join(root,dir)
new_dir_path = os.path.join(root,newdir)
os.rename(old_dir_path,new_dir_path)
print "replaced: ",bad_dir_char,"

I get a "local variable 'newdir' referenced before assignment" error.

I am somewhat new to programming and I do not understand a lot about
where variables live and where they do not. I know the difference
between global and function specific variables, but I was under the
impression that if a local variable lived within a function that I could
access its contents *anywhere* in that function. This is obviuously
wrong, could someone expound upon this? Not that it matters, but below
is the entire function that I'm playing with. I have a working version
of it, but I'm cleaning it up a bit (I know that that is a bad thing,
but it helps me learn more about programming).

import os, re, string
print
setpath = raw_input("Path to the Directory to act on: ")
def clean_names(setpath):
bad = re.compile(r'%2f|%25|%20|[*?<>/\|\\]') # bad characters
for root, dirs, files in os.walk(setpath):
for dir in dirs:
bad_dir_chars = bad.findall(dir)
for bad_dir_char in bad_dir_chars:
newdir = dir.replace(bad_dir_char,'-')
if newdir != dir:
old_dir_path = os.path.join(root,dir)
new_dir_path = os.path.join(root,newdir)
os.rename(old_dir_path,new_dir_path)
print "replaced: ",bad_dir_char," in dir ",dir," ",

Your problem is because Python has a bit of a split personality
about local variables. On one hand, if a name is assigned
anywhere in a function or a method, it's a local variable (unless
there's a global statement, of course.) This analysis is done
at compile time.

On the other hand, the variable does not exist until it's
assigned at run time, so if your assignment is in an if statement
(which yours is) then it's possible that it won't get assigned
before it's used. That's what is happening here.

John Roth
 
A

Alex Martelli

Michael said:
This has nothing to do with where variables live. What is happening is
when bad_dir_chars is empty, newdir doesn't get assigned in your for loop.

Right -- and when bad_dir_chars has more than one character, all
but the last one are basically ignored (they ARE used to laboriously
compute many versions of newdir, but all versions except the last
one are thrown away).

Do, instead:

import string

transbad = string.maketrans(bad_dir_chars, '-'*len(bad_dir_chars))

newdir = dir.translate(transbad)


this no doubt has the effect you were looking for...


Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top