Discussion:
[Tutor] variable existence q
Clayton Kirkwood
2015-08-15 20:51:50 UTC
Permalink
10 top_directory = "/users/Clayton/Pictures"

def override_defaults():
56 return( top_directory, filetypes, target_directory )

80 top_directory, filetypes, target_directory = override_defaults()


File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 80, in <module>
top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 56, in override_defaults
return( top_directory, filetypes, target_directory )
UnboundLocalError: local variable 'top_directory' referenced before
assignment

I am facing the above error:
10 occurs first
80 then runs
56 appears to not work, the function logically does nothing
I thought that variables in the main were visible to defined functions in
the same file, as long as the assignment occurs physically before use. When
debugging, inside of override_defaults sees the correct value.
What am I not seeing?

TIA,
Clayton

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Peter Otten
2015-08-15 21:11:36 UTC
Permalink
Post by Clayton Kirkwood
10 top_directory = "/users/Clayton/Pictures"
56 return( top_directory, filetypes, target_directory )
80 top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 80, in <module>
top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 56, in override_defaults
return( top_directory, filetypes, target_directory )
UnboundLocalError: local variable 'top_directory' referenced before
assignment
10 occurs first
80 then runs
56 appears to not work, the function logically does nothing
I thought that variables in the main were visible to defined functions in
the same file, as long as the assignment occurs physically before use.
I don't think it's relevant here, but generally speaking the order in the
file doesn't matter, only the order of execution matters. For example
Post by Clayton Kirkwood
def f(): return x
...
Post by Clayton Kirkwood
x = 42
print(f())
42

Even though the assignment to x occurs physically after the function
definition, as the function is invoked after that assignment you don't get a
NameError.
Post by Clayton Kirkwood
When debugging, inside of override_defaults sees the correct value.
What am I not seeing?
There must be an assignment to top_directory inside override_defaults().
... if False: x = 42 # this turns x into a local name
... return x
...
Post by Clayton Kirkwood
x = 42
f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f
UnboundLocalError: local variable 'x' referenced before assignment
Post by Clayton Kirkwood
x # the global x is defined, but not visible inside the function
42

Wether a name is local to the function or global is determined statically by
Post by Clayton Kirkwood
x = 42
class A: x = x
...
Post by Clayton Kirkwood
A.x
42
Post by Clayton Kirkwood
def f(): x = x
...
Post by Clayton Kirkwood
f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in f
UnboundLocalError: local variable 'x' referenced before assignment



_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Mark Lawrence
2015-08-15 21:47:48 UTC
Permalink
Post by Peter Otten
Post by Clayton Kirkwood
10 top_directory = "/users/Clayton/Pictures"
56 return( top_directory, filetypes, target_directory )
80 top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 80, in <module>
top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 56, in override_defaults
return( top_directory, filetypes, target_directory )
UnboundLocalError: local variable 'top_directory' referenced before
assignment
10 occurs first
80 then runs
56 appears to not work, the function logically does nothing
I thought that variables in the main were visible to defined functions in
the same file, as long as the assignment occurs physically before use.
I don't think it's relevant here, but generally speaking the order in the
file doesn't matter, only the order of execution matters. For example
Post by Clayton Kirkwood
def f(): return x
...
Post by Clayton Kirkwood
x = 42
print(f())
42
Even though the assignment to x occurs physically after the function
definition, as the function is invoked after that assignment you don't get a
NameError.
Post by Clayton Kirkwood
When debugging, inside of override_defaults sees the correct value.
What am I not seeing?
There must be an assignment to top_directory inside override_defaults().
... if False: x = 42 # this turns x into a local name
... return x
...
Post by Clayton Kirkwood
x = 42
f()
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f
UnboundLocalError: local variable 'x' referenced before assignment
Post by Clayton Kirkwood
x # the global x is defined, but not visible inside the function
42
Wether a name is local to the function or global is determined statically by
Post by Clayton Kirkwood
x = 42
class A: x = x
...
Post by Clayton Kirkwood
A.x
42
Post by Clayton Kirkwood
def f(): x = x
...
Post by Clayton Kirkwood
f()
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in f
UnboundLocalError: local variable 'x' referenced before assignment
Your explanation doesn't make any sense to me. I'd have thought that
having assigned top_directory at line 10, but then trying to reassign it
at line 80, means that the function now knows nothing about it, hence
the error.
--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Emile van Sebille
2015-08-15 22:08:59 UTC
Permalink
Post by Mark Lawrence
Post by Clayton Kirkwood
10 top_directory = "/users/Clayton/Pictures"
56 return( top_directory, filetypes, target_directory )
80 top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 80, in <module>
top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 56, in override_defaults
return( top_directory, filetypes, target_directory )
UnboundLocalError: local variable 'top_directory' referenced before
assignment
<snip>
Post by Mark Lawrence
Your explanation doesn't make any sense to me. I'd have thought that
having assigned top_directory at line 10, but then trying to reassign it
at line 80, means that the function now knows nothing about it, hence
the error.
Assigning to a variable inside a function makes that variable local,
which must have happened as per the error message:
UnboundLocalError: local variable 'top_directory'...

As Peter noted, somewhere within override_defaults there's an assignment
to it. Changing to
def override_defaults(top_directory=top_directory):
should initialize it in case the assignment path isn't processed.

Emile


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Clayton Kirkwood
2015-08-15 22:38:31 UTC
Permalink
top_directory = "/users/Clayton/Pictures"
target_directory = top_directory #directory we are checking
filetypes = ('jpg', 'png', 'avi', 'mp4', 'mov', 'bmp')

imports...

def override_defaults():
with open( user_preferences ) as f:
for line in f.readline():
llist = line.split()
if llist[0] == '#': #comment line to ignore
continue
elif llist[0] == 'top_directory':
if len(llist) == 1:
pass
else:
top_directory = llist[1]
elif llist[0] == 'target_directory':
if len(llist) == 1:
pass
else:
target_directory = llist[1]
else: #assume only filetypes now or until next comment or
other keyword
if llist[0] == 'filetypes': #allow keyword w/wo following
types
if llist.length() == 1:
continue #assume user plans either not
interested in types or types coming on later line
llist.pop([0]) #skip keyword and start
recording
filetypes.append(llist[0:]) #assume line contains 0,
consumes blank lines, or more media files w/wo leading dot
continue
56 return( top_directory, filetypes, target_directory )
80 top_directory, filetypes, target_directory = override_defaults()>

The error message again is:
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 80, in <module>
top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 56, in override_defaults
return( top_directory, filetypes, target_directory )
UnboundLocalError: local variable 'top_directory' referenced before
assignment
Post by Mark Lawrence
Your explanation doesn't make any sense to me. I'd have thought that
having assigned top_directory at line 10, but then trying to reassign
it at line 80, means that the function now knows nothing about it,
hence the error.
Assigning to a variable inside a function makes that variable local, which
must
UnboundLocalError: local variable 'top_directory'...
As Peter noted, somewhere within override_defaults there's an assignment
to it. Changing to
should initialize it in case the assignment path isn't processed.
Above is the actual code. The file /user..../user preferences exists but is
empty. Defaults are at the top. For what it is worth, the debugger stopped
in the function shows the values stated as the defaults at the top. If I
understand correctly, the readline() would drop out, but even if it doesn't
no assignments would be made for top_directory or target_directory. I
thought that top_directory was global to this file. I am hearing that it
doesn't matter whether the assignment is above or below the function
definition. I should be able to use the tuple for the results of the call,
right? In this case, no assignment was made. If I understand, the function
sees the global. If that is changed inside the function, doesn't it change
the global?

Crk
Emile
_______________________________________________
https://mail.python.org/mailman/listinfo/tutor
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Emile van Sebille
2015-08-15 22:56:05 UTC
Permalink
Post by Clayton Kirkwood
top_directory = "/users/Clayton/Pictures"
target_directory = top_directory #directory we are checking
filetypes = ('jpg', 'png', 'avi', 'mp4', 'mov', 'bmp')
imports...
llist = line.split()
if llist[0] == '#': #comment line to ignore
continue
pass
top_directory = llist[1]
pass
target_directory = llist[1]
else: #assume only filetypes now or until next comment or
other keyword
if llist[0] == 'filetypes': #allow keyword w/wo following
types
continue #assume user plans either not
interested in types or types coming on later line
llist.pop([0]) #skip keyword and start
recording
filetypes.append(llist[0:]) #assume line contains 0,
consumes blank lines, or more media files w/wo leading dot
continue
56 return( top_directory, filetypes, target_directory )
80 top_directory, filetypes, target_directory = override_defaults()>
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 80, in <module>
top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 56, in override_defaults
return( top_directory, filetypes, target_directory )
UnboundLocalError: local variable 'top_directory' referenced before
assignment
Post by Mark Lawrence
Your explanation doesn't make any sense to me. I'd have thought that
having assigned top_directory at line 10, but then trying to reassign
it at line 80, means that the function now knows nothing about it,
hence the error.
Assigning to a variable inside a function makes that variable local, which
must
UnboundLocalError: local variable 'top_directory'...
As Peter noted, somewhere within override_defaults there's an assignment
to it. Changing to
should initialize it in case the assignment path isn't processed.
Above is the actual code. The file /user..../user preferences exists but is
empty. Defaults are at the top. For what it is worth, the debugger stopped
in the function shows the values stated as the defaults at the top. If I
understand correctly, the readline() would drop out, but even if it doesn't
no assignments would be made for top_directory or target_directory.
Actual assignment isn't required to make it a local variable -- only the
fact that it appears on the left hand side of an assignment statement
with the function.
Post by Clayton Kirkwood
I thought that top_directory was global to this file. I am hearing that
it doesn't matter whether the assignment is above or below the function
definition. I should be able to use the tuple for the results of the call,
right? In this case, no assignment was made. If I understand, the function
sees the global.
Not any more -- it's a local variable because the assignment, while not
executed, exists.
Post by Clayton Kirkwood
If that is changed inside the function, doesn't it change
the global?
Only if you include the globals statement before the variable is referenced.

Emile


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Mark Lawrence
2015-08-15 23:05:16 UTC
Permalink
Post by Clayton Kirkwood
top_directory = "/users/Clayton/Pictures"
target_directory = top_directory #directory we are checking
filetypes = ('jpg', 'png', 'avi', 'mp4', 'mov', 'bmp')
imports...
llist = line.split()
if llist[0] == '#': #comment line to ignore
continue
pass
top_directory = llist[1]
pass
target_directory = llist[1]
else: #assume only filetypes now or until next comment or
other keyword
if llist[0] == 'filetypes': #allow keyword w/wo following
types
continue #assume user plans either not
interested in types or types coming on later line
llist.pop([0]) #skip keyword and start
recording
filetypes.append(llist[0:]) #assume line contains 0,
consumes blank lines, or more media files w/wo leading dot
continue
56 return( top_directory, filetypes, target_directory )
80 top_directory, filetypes, target_directory = override_defaults()>
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 80, in <module>
top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 56, in override_defaults
return( top_directory, filetypes, target_directory )
UnboundLocalError: local variable 'top_directory' referenced before
assignment
Post by Mark Lawrence
Your explanation doesn't make any sense to me. I'd have thought that
having assigned top_directory at line 10, but then trying to reassign
it at line 80, means that the function now knows nothing about it,
hence the error.
Assigning to a variable inside a function makes that variable local, which
must
UnboundLocalError: local variable 'top_directory'...
As Peter noted, somewhere within override_defaults there's an assignment
to it. Changing to
should initialize it in case the assignment path isn't processed.
Above is the actual code. The file /user..../user preferences exists but is
empty. Defaults are at the top. For what it is worth, the debugger stopped
in the function shows the values stated as the defaults at the top. If I
understand correctly, the readline() would drop out, but even if it doesn't
no assignments would be made for top_directory or target_directory. I
thought that top_directory was global to this file. I am hearing that it
doesn't matter whether the assignment is above or below the function
definition. I should be able to use the tuple for the results of the call,
right? In this case, no assignment was made. If I understand, the function
sees the global. If that is changed inside the function, doesn't it change
the global?
Crk
You are trying to change it at line 80. Do you really want to do that?
If no I suggest you spell it TOP_DIRECTORY to indicate that it is a
constant that should not be changed.
--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Clayton Kirkwood
2015-08-16 03:27:53 UTC
Permalink
-----Original Message-----
Behalf Of Mark Lawrence
Sent: Saturday, August 15, 2015 4:05 PM
Subject: Re: [Tutor] variable existence q
Post by Clayton Kirkwood
top_directory = "/users/Clayton/Pictures"
target_directory = top_directory #directory we are checking
filetypes = ('jpg', 'png', 'avi', 'mp4', 'mov', 'bmp')
imports...
llist = line.split()
if llist[0] == '#': #comment line to ignore
continue
pass
top_directory = llist[1]
pass
target_directory = llist[1]
else: #assume only filetypes now or until next comment or
other keyword
if llist[0] == 'filetypes': #allow keyword w/wo
following types
continue #assume user plans either not
interested in types or types coming on later line
llist.pop([0]) #skip keyword and start
recording
filetypes.append(llist[0:]) #assume line contains 0,
consumes blank lines, or more media files w/wo leading dot
continue
56 return( top_directory, filetypes, target_directory )
80 top_directory, filetypes, target_directory = override_defaults()>
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 80, in <module>
top_directory, filetypes, target_directory = override_defaults()
File "C:/Users/Clayton/python/find picture duplicates/find picture
duplicates", line 56, in override_defaults
return( top_directory, filetypes, target_directory )
UnboundLocalError: local variable 'top_directory' referenced before
assignment
Post by Mark Lawrence
Your explanation doesn't make any sense to me. I'd have thought
that having assigned top_directory at line 10, but then trying to
reassign it at line 80, means that the function now knows nothing
about it, hence the error.
Assigning to a variable inside a function makes that variable local, which
must
UnboundLocalError: local variable 'top_directory'...
As Peter noted, somewhere within override_defaults there's an
assignment to it. Changing to
should initialize it in case the assignment path isn't processed.
Above is the actual code. The file /user..../user preferences exists
but is empty. Defaults are at the top. For what it is worth, the
debugger stopped in the function shows the values stated as the
defaults at the top. If I understand correctly, the readline() would
drop out, but even if it doesn't no assignments would be made for
top_directory or target_directory. I thought that top_directory was
global to this file. I am hearing that it doesn't matter whether the
assignment is above or below the function definition. I should be able
to use the tuple for the results of the call, right? In this case, no
assignment was made. If I understand, the function sees the global. If
that is changed inside the function, doesn't it change the global?
Crk
You are trying to change it at line 80. Do you really want to do that?
If no I suggest you spell it TOP_DIRECTORY to indicate that it is a
constant
that should not be changed.
No, I am saying at the top that the defaults are set, and if running the
override_defaults changes them, then they get changed. I have defaults, and
I allow the user to override them.

crk
--
My fellow Pythonistas, ask not what our language can do for you, ask what
you can do for our language.
Mark Lawrence
_______________________________________________
https://mail.python.org/mailman/listinfo/tutor
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Peter Otten
2015-08-16 09:10:20 UTC
Permalink
Post by Clayton Kirkwood
Above is the actual code.
Clayton, try to understand how scoping works in Python before you go back to
your actual code. Can you predict what the following snippet will produce?

x = "first global"

def f():
return x

def g():
return x
x = "local"

x = "second global"

print(f())
print(g())

What will the first print() produce?

'first global', i. e. the value the name x is bound to when f is created, or
'second global', the value the name x is bound to when f() is invoked?

What will g() try to return? The local variable x or the global variable x?
Does it succeed? If not, why?

Once you are clear about both problems fixing your actual code should be
easy.

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Steven D'Aprano
2015-08-16 09:24:15 UTC
Permalink
Post by Clayton Kirkwood
top_directory = "/users/Clayton/Pictures"
target_directory = top_directory #directory we are checking
filetypes = ('jpg', 'png', 'avi', 'mp4', 'mov', 'bmp')
imports...
llist = line.split()
if llist[0] == '#': #comment line to ignore
continue
pass
top_directory = llist[1]
This line tells the compiler that top_directory must be a local
variable, since you assign to it within a function. As a local variable,
it only gets set on *some* paths through the function, so you get an
error, same as this:


def example(n):
if n % 2 == 0:
td = "test"
else:
pass
return td # fails half the time

Python uses a simple rule to decide whether or not a variable is a local
or not. If the variable is assigned to *anywhere* in the function, it is
treated as local. Even if the line is never actually executed! (For this
purpose, "del" is treated as a de facto assignment too.) So you can even
do this:

x = 23

def test():
return x
# code below here is never executed
if False:
# and even if it were, code inside this block is never executed
x = 42 # makes x a local variable

and calling test() will now give an UnboundLocalError.

To tell Python not to treat it as a local, you need to declare it
global. Same with target_directory. So one solution is to put this as
the first line of your function:

global top_directory, target_directory


(Technically, you can put it anywhere inside the function, yes, even
after the return statement, and it will have the same effect. But don't
do that. Always put it at the start.)


Another solution is to write the function like this:

def override_defaults():
top = top_directory
target = target_directory
with open( user_preferences ) as f:
for line in f: # no need for f.readlines
line = line.strip() # ignore leading and trailing whitespace
words = line.split()
if words[0].startswith('#'): #comment line to ignore
continue
elif words[0] == 'top_directory':
top = words[1]
[ ... ]
return (top, file_types, target)
--
Steve
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Continue reading on narkive:
Loading...