Re: [Tutor] variable existence q

2015-08-16 Thread Steven D'Aprano
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

2015-08-16 Thread Peter Otten
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

2015-08-15 Thread Clayton Kirkwood


> -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

2015-08-15 Thread Mark Lawrence

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

2015-08-15 Thread Emile van Sebille

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

2015-08-15 Thread Clayton Kirkwood
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

2015-08-15 Thread Emile van Sebille

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

2015-08-15 Thread Mark Lawrence

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

2015-08-15 Thread Peter Otten
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