Tkinter: Changing a variable within a function - python

I know this kind of question gets asked all the time but either i've been unable to come across the answer i need, or i've been unable to understand it when i did.
I want to be able to do something like:
spam = StringVar()
spam.set(aValue)
class MyScale(Scale):
def __init__(self,var,*args,**kwargs):
Scale.__init__(self,*args,**kwargs)
self.bind("<ButtonRelease-1>",self.getValue)
self.set(var.get())
def getValue(self,event):
## spam gets changed to the new value set
## by the user manipulating the scale
var.set(self.get)
eggs = MyScale(spam,*args,**kwargs)
eggs.pack()
Of course, i get back "NameError: global name 'var' is not defined."
How do i get around the inability to pass arguments to getValue? I've been warned against using global variables but is that my only option? Is it setting up a separate scale class for each variable i want to change? I get the feeling i'm missing something thats right under my nose...
edit:
is this what you mean?
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\...\interface.py", line 70, in getValue
var.set(self.get)
NameError: global name 'var' is not defined
Sorry, I've only been programming a month and some of the jargon still escapes me.

Please give this a shot.
Lots of example code out there generously uses globals, like your "var" variable.
I have used your var argument to act as a pointer back to the original spam object; assigned to self.var_pointer within the MyScale class.
The code below will change the value of 'spam' (and 'eggs') on the scale's ButtonRelease.
You can check out the value by typing eggs.get() or spam.get() to see the changed value.
from Tkinter import *
root = Tk()
aValue = "5"
spam = StringVar()
spam.set(aValue)
class MyScale(Scale):
def __init__(self,var,*args,**kwargs):
self.var_pointer = var
Scale.__init__(self,*args,**kwargs)
self.bind("<ButtonRelease-1>",self.getValue)
self.set(var.get())
def getValue(self,event):
## spam gets changed to the new value set
## by the user manipulating the scale
self.var_pointer.set(self.get())
eggs = MyScale(spam)
eggs.pack(anchor=CENTER)

Let's look at this method function
def getValue(self,event):
## spam gets changed to the new value set
## by the user manipulating the scale
var.set(self.get)
The var.set(self.get) line has exactly two local variables available:
self
event
The variable var is not local to this method function. Perhaps it was used elsewhere in the class or script, but it's not local here.
It may, possibly, be global, but that's a bad practice.
I'm not sure why you'd think the variable var would be known in this context.

Related

Scopes and Customizing Open (learning Python p. 539)

I'm a bit confused about a code in the book "Learning Python", p. 539.
As far as I know assignments within a function are only in this local scope. So if I want to change a global one I first have to declare it global. But why does the following code change the builtin.open() to custom completely once called?
import builtins
def makeopen(id):
original = builtins.open
def custom(*pargs, **kargs):
print('Custom open call %r: ' % id, pargs, kargs)
return original(*pargs, **kargs)
builtins.open = custom
If I call makeopen('spam') and a F = open('text.txt') afterwards I get the custom call. So the builtin.open() has been changed in the whole script after the makeopen('spam'). Why?
And if I would make some more makeopen('xx') one builtin.open('text.txt') would print the custom call for every created makeopen. Why?
Comparing this code to
x = 99
def changing():
x = 88
changing()
print(x)
doesnt even help me. Isn't it the same but with an x instead of builtin.open()?
A variable is considered local if you assign to it anywhere in the function, unless you declare it global.
In your first piece of code, you never assign anything to builtins, so it's not considered local. You just change one of its attributes, open.
The rule is respected!
In your second piece of code, you assign something to x in x = 88, so it is considered local.
When you call makeopen, you replace the original, global open with custom. custom, when executed, prints its name and calls the original open.
If you call makeopen a second time, it will create a second, different custom function, and make the name builtins.open refer to it. When you call this function, it will print its name, then call original, which is what builtins.open referred to when it was created - and that is your first custom function, which will print its name and call the original open.
So, successive calls to makeopen create a chain of functions, and calling open will make each of them run and call its predecessor.

Python use input to select local variable inside another function

All, I have this request but first I will explain what I'm trying to achieve. I coded a python script with many global variables but also many methods defined inside different modules (.py files).
The script sometimes moves to a method and inside this method I call another method defined in another module. The script is quite complex.
Most of my code is inside Try/Except so that every time an exception is triggered my code runs a method called "check_issue()" in which I print to console the traceback and then I ask myself if there's any variable's value I want to double check. Now, I read many stackoverflow useful pages in which users show how to use/select globals(), locals() and eval() to see current global variables and local variables.
What I would specifically need though is the ability to input inside method "check_issue()" the name of a variable that may be defined not as global and not inside the method check_issue() either.
Using classes is not a solution since I would need to change hundreds of lines of code.
These are the links I already read:
Viewing all defined variables
Calling variable defined inside one function from another function
How to get value of variable entered from user input?
This is a sample code that doesn't work:
a = 4
b = "apple"
def func_a():
c = "orange"
...
check_issue()
def check_issue():
print("Something went wrong")
var_to_review = input("Input name of var you want to review")
# I need to be able to enter "c" and print the its value "orange"
print(func_a.locals()[var_to_review ]) # this doesn't work
Could somebody suggest how to fix it?
Many thanks
When you call locals() inside check_issue(), you can only access to the locals of this function, which would be : ['var_to_review'].
You can add a parameter to the check_issue function and pass locals whenever you call it.
a = 4
b = "apple"
def func_a():
c = "orange"
check_issue(locals())
def check_issue(local_vars):
print("Something went wrong")
var_to_review = input("Input name of var you want to review")
print(local_vars[var_to_review])

Python: cannot return a value assigned inside of a function outside of that function to later use

def program(n):
name = input("What is your name? >")
return name
print(name)
I have a code that i am trying to execute very similar to this. When executing it, it will not return the variable 'name' i used in the function in order to use that variable outside the function. Why is this?
I am super new to coding by the way so please excuse me if i made a stupid mistake.
When you run your program, you need to assign the result (i.e. whatever is returned in your program, to another variable). Example:
def get_name():
name = input('Name please! ')
return name
name = get_name()
print('Hello ' + name)
Pssst.. I took your function parameter n away since it was not being used for anything. If you're using it inside your actual program, you should keep it :)
For a bit of a more in-depth explanation...
Variables that are declared inside your neat little function over there can't be seen once you come out of it (though there are some exceptions that we don't need to get into right now). If you're interested in how this works, it's known as "variable scope."
To execute the content of a function you need to make a call to the function and assign the return value to some variable. To fix your example, you would do:
def get_name():
name = input("What is your name? >")
return name
name = get_name()
print(name)
I have changed the function name from program() to get_name() seeing as program() is a ambiguous name for a function.
This snippet will make a call to the get_name() function and assign the return value to the variable name. It is important to note, that the name variable inside the function is actually a different variable to the one that we are assigning to outside the function. Note: I have removed the argument n from get_name() since it was not being used.

Name Error when passing a parameter?

I am writing a program and keep on getting trouble with the error:
File "C:/Users//Documents///", line 47, in <module>
print(operations(sorted_list_desc))
NameError: name 'sorted_list_desc' is not defined
Even though you can not see the file I am working with, I have provided my code. I am supposed to loop the years and randomly choose an operator for each of the years. However, I keep on getting the error above. Any ideas why I keep on getting it?
import csv
#List to store different operators
list_operators = ["+","-","*","/"]
#Function to read file of list
def read_file():
#List to store data
sorted_list_desc = []
year = csv_file.readline()
population = csv_file.readline()
return sorted_list_desc
print(read_file())
def operations(sorted_list_desc):
for i in range(len(sorted_list_desc)):
operator = random.choice(list_operator)
return operator
print(operations(sorted_list_desc))
##
sorted_list_desc is generated by read_file(). Change your last line to:
print(operations(read_file()))
The line:
print(read_file())
does not magically created a global object withe name sorted_list_desc.
You need to hand it over explicitly to operations().
Alternatively, you could write:
sorted_list_desc = read_file()
print(operations(sorted_list_desc))
You have only assigned sorted_list_desc inside your function read_file(). Thus, your error is telling you that sorted_list_desc is not assigned to anything outside your function's scope. See Python scoping rules, and notice that you don't even need to pass sorted_list_desc as a parameter because it is assigned inside your function anyways.
Looks like sorted_list_desc is defined within the scope of your read_file() function and thus you can't reference it outside of that function. You can call print(operations(sorted_list_desc)) within 'read_file()', or you can define sorted_list_desc = [] at a global scope.

creating and using a driver function. How does it work?

I am new to python and have been shown 'drivers' for running functions without entering them into the command line,
I don`t understand the concept of drivers or how to type them out correctly, any kind of feedback on how to use them would be great!.
What I don't understand is how entering the function makeGreyscaleThenNegate(pic) can call the def function makeGreyscaleThenNegate(picture): when the input values are different (pic) versus (picture). (I guess this is because I don't know how the 'driver' function works.)
Here is what i've been shown
def driverGrey():
pic=makePicture(pickAFile())
repaint(pic)
makeGreyscaleThenNegate(pic)
repaint(pic)
def makeGreyscaleThenNegate(picture):
for px in getPixels(picture):
lum=(getRed(px)+getGreen(px)+getBlue(px)/3
lum=255-lum
setColor(px,makeColor(lum,lum,lum))
My belief is for this to work,(pic) would already have been named/defined prior to creating the 'driver' function? I just am not sure how (pic) and (picture) are referring to the same file, or am I completely mis-interpreting this..
This is really CS101 and nothing Python-specific actually. A function is a name for a code snippet. The names of the variables you pass as arguments to the function and the names of the arguments in the function are totally unrelated, they are just names. What happens in the above snippet:
def driverGrey():
pic=makePicture(pickAFile())
# 1. call a function named 'pickAFile' which I assume returne a file or filename
# 2. pass the file or filename to the function named 'makePicture' which obviously
# returns a 'picture' object (for whatever definition of a 'picture object')
# 3. binds the 'picture object' to the local name 'pic'
(snip...)
makeGreyscaleThenNegate(pic)
# 1. pass the picture object to the function named 'makeGreyscaleThenNegate'.
#
# At that time we enter the body of the 'makeGreyscaleThenNegate' function,
# in which the object known as 'pic' here will be bound to the local
# name 'picture' - IOW at that point we have two names ('pic' and 'picture')
# in two different namespaces ('driverGrey' local namespace and
# 'makeGreyscaleThenNegate' local namespace) referencing the same object.
#
# 2. 'makeGreyscaleThenNegate' modifies the object.
#
# 3. when 'makeGreyscaleThenNegate' returns, it's local namespace is destroyed
# so we only have the local 'pic' name referencing the picture object,
# and the control flow comes back here.
(snip...)
pic and picture are just names or labels. You can call a chunk of data whatever you want. For example, a Spaniard might call a bottle of milk "leche" whereas a Frenchman might call it "lait".
The same thing applies to Python. You have some sort of "picture" object, and throughout your program, you're calling it by different names. In the driverGray function, you call it pic, and in the makeGrayscaleThenNegate function, you call it picture. Different name, same object.
If I were to do this:
pic = makePicture(pickAFile())
b = pic
c = b
...both pic, b, and c are all referring to the exact same "thing". If I make a change to b by doing something like b.var = 13, both c and pic will change too.
(Note: if you did something like c = 1, then you're saying that c now means a number, rather then a picture object. The pic and b variables are unaffected.
Here's a metaphor: if somebody were to poison the milk, then it doesn't matter what the Spaniard or the Frenchman calls the milk -- it's poisoned, regardless of the particular name.
In your case, when you do makeGreyscaleThenNegate(pic) inside the first function, you are saying that you "pass in" a picture object (which you happen to call pic). The makeGrayscaleThenNegate function is defined as def makeGreyscaleThenNegate(picture):. This means that the first argument that is passed in will be called "picture" for the duration of that function.

Categories

Resources