Re: [Tutor] variable existence q
On Sat, Aug 15, 2015 at 03:38:31PM -0700, Clayton Kirkwood wrote: > 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] 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 - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] variable existence q
Clayton Kirkwood wrote: >> > 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 - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] variable existence q
> -Original Message- > From: Tutor [mailto:tutor-bounces+crk=godblessthe...@python.org] On > Behalf Of Mark Lawrence > Sent: Saturday, August 15, 2015 4:05 PM > To: tutor@python.org > Subject: Re: [Tutor] variable existence q > > On 15/08/2015 23:38, Clayton Kirkwood wrote: > > 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 > > 56return( 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 > > 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 > > > >>> 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. > > > > 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 > > ___ > Tutor maillist - Tutor@python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] variable existence q
On 15/08/2015 23:38, Clayton Kirkwood wrote: 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 56return( 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 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 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. 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 - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] variable existence q
On 8/15/2015 3:38 PM, Clayton Kirkwood wrote: 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 56return( 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 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 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. 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. 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. 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 - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] variable existence q
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 56return( 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 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 > > 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. 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 > > > ___ > Tutor maillist - Tutor@python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] variable existence q
On 8/15/2015 2:47 PM, Mark Lawrence wrote: On 15/08/2015 22:11, Peter Otten wrote: Clayton Kirkwood wrote: 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 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 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 - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] variable existence q
On 15/08/2015 22:11, Peter Otten wrote: Clayton Kirkwood wrote: 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 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. 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 def f(): return x ... 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. 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(). This assignment turns top_directory into a local variable: def f(): ... if False: x = 42 # this turns x into a local name ... return x ... x = 42 f() Traceback (most recent call last): File "", line 1, in File "", line 3, in f UnboundLocalError: local variable 'x' referenced before assignment 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 the compiler. This is different from class definitions. Compare: x = 42 class A: x = x ... A.x 42 def f(): x = x ... f() Traceback (most recent call last): File "", line 1, in File "", 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 - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] variable existence q
Clayton Kirkwood wrote: > 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 > 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. 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 >>> def f(): return x ... >>> 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. > 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(). This assignment turns top_directory into a local variable: >>> def f(): ... if False: x = 42 # this turns x into a local name ... return x ... >>> x = 42 >>> f() Traceback (most recent call last): File "", line 1, in File "", line 3, in f UnboundLocalError: local variable 'x' referenced before assignment >>> 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 the compiler. This is different from class definitions. Compare: >>> x = 42 >>> class A: x = x ... >>> A.x 42 >>> def f(): x = x ... >>> f() Traceback (most recent call last): File "", line 1, in File "", line 1, in f UnboundLocalError: local variable 'x' referenced before assignment ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor