module does not see my values inside the main code - python

I'm very new to Python and currently am building a GUI interface in Tkinter and have a fully working code for it. I thought it would be nice to have a button work from keyboard by pressing "Enter" key.
The code line for that is:win.bind('<Return>', testButton.functionName)
Then you just put "event" in function bracket aka functionName(event) And everything works great.
The issue is that now it does not work when you press the button inside the GUI interface what means I need to duplicate and reName one of the functions to have both.
Since it is an identical code, it would make more sense to have it as a module. However, when I import my module it does not seem to see the rest of my code and claims that my variables do not exist.
Here is a simplified example of how I'm doing it.
My module saved as moduleTest:
def test():
sum = a + b
return sum
Main program:
import moduleTest
a = 10
b = 12
moduleTest.test()
print test()
It keeps claiming that a and b are not defined.
I'm clearly misunderstanding how modules work cause in my mind when I import a module it should simply import the whole code and do the same thing as this:
import moduleTest
a = 10
b = 12
def test():
sum = a + b
return sum
print test()
What am I misunderstanding and doing wrong?

Python globals are global to each module, not to the whole program.
The usual way to deal with this is to not use globals.
For your toy example, you can def test(a, b): and then call test(a, b) from your main module, and that's typically the right solution, but it isn't always appropriate.
Other options are:
Use a class, and pass the values in when you create the instance.
Store the globals that need to be shared in a third module, which both main and moduleTest can import thirdmodule and access as thirdmodule.a. This is often appropriate for cases like shared configuration values.
Store the globals as attributes of some other thing both pieces of code already have access to.

As #abarnert points out, globals are global to each module. In order to solve this problem you can use:
def test(a, b):
sum = a + b
return sum
And
import moduleTest
a = 10
b = 12
print(moduleTest.test(a, b))
I would like to point out you should not call your variables sum because this already is an existing function which you're overwriting.

Here are several separate fragments of my code to give you an idea:
item = "SNAKE"
oldString = "-" * (len(item))
blank = "-" * (len(item))
guesses = 10
def gameOn():
global guesses
global oldString
newString = ""
i = 0
x = len(item)
hanged = ""
readString = answerIn.get().upper()
winner = 1
if not readString:
if guesses == 10:
pass
else:
hanged = (HANGMAN[(len(HANGMAN) -1) - guesses])
hangedOutput.config(state=NORMAL)
hangedOutput.delete("1.0",END)
hangedOutput.insert(END,hanged)
hangedOutput.config(state=DISABLED)
error.config(state=NORMAL)
error.delete(0,END)
error.insert(0,"Please enter the value.")
error.config(state=DISABLED)
win = Tk()
answerIn = Entry(win,width = 3, border = 2)
answerIn.focus_set()
answerIn.grid(row=2, column=0, pady = 10, padx = 200, sticky = W)
win.mainloop()
When I turn it into a module it keeps asking not just for item and oldString definitions but also for answerIn, hangedOutput and etc which are part of Tkinter labels.

Related

Python random module doesn't randomize more than once

in this code there are two Random Number Generators. One in the first line, the other in the function btn_yes.
Both RNG's work fine, the print(nb) directly after the generator in the function btn_yes displays a random number like it should.
However, when btn_press is activated after btn_yes was activated (like it should in the program), the value of nb doesn't change, no matter how often i execute btn_yes. btn_press just uses the same number that was generated by the first RNG.
What am I missing?
nb = random.randrange(0, 11)
def btn_press():
guess = int(entry.get())
print(guess)
if guess < nb:
answ["text"] = "Higher!"
elif guess > nb:
answ["text"] = "Lower!"
elif guess == nb:
answ["text"] = "Correct!"
btn2["bg"] = "#FF6C6C"
btn3["bg"] = "#32FF00"
def btn_no():
window.destroy()
def btn_yes():
answ["text"] = "Next Round! Type in a new number!"
btn2["bg"] = "#464646"
btn3["bg"] = "#464646"
nb = random.randrange(0, 11)
entry.delete(0, tk.END)
print(nb)
The problem here is that when you change a global variable inside a function, you need to put global <variablename> as the first line in the function. Otherwise, Python assumes you meant to make a new variable with that name that is only in scope inside the function, and the global variable remains unchanged.
You can see this by printing nb inside the function btn_yes(); you should see that it has a different value each time (and not the same value as the global nb).
In this case, if you put global nb as the first line in btn_yes(), it should have the desired effect.
See using global variables in a function

Python - NameError 'name_q' is not defined

So I have been playing around with coding and so on and I just do like really random stuff, right now im doing so I just do random names inbuilt with my script basically Barry can turn to Henry or B.a.r.r.y. Nothing special.
The issue though is that whenever I try to print out or use name_q.get() in another method, it gives me a error saying NameError. What did go wrong?
def main():
names = name_q.get()
log(names)
exit()
def test():
name_q = Queue()
user_input = int(input('How many random names you wanna make out of Barry? [NUMBERS] \n'))
Names= "barry"
generator = NamesGenerator(Names).generate()
for i in range(0, user_input):
name_q.put(generator[i])
main()
The variable name_q is local to the function test. It doesn't exist in function main.
You have to give it as a parameter:
def main(name_q):
names = name_q.get()
log(names)
def test():
name_q = Queue()
user_input = int(input('How many random names you wanna make out of Barry? [NUMBERS] \n'))
names= "barry"
generator = NamesGenerator(names).generate()
for i in range(0, user_input):
name_q.put(generator[i])
main(name_q)
NB: this has nothing to do with your problem but please put capital letters only at the beginning of class names, not to any variable. If you don't, this will lead to misunderstanding when people read your code.
Moreover, Python code should be written with a maximum of 79 columns, as indicated in PEP8.

Python function not working - Tkinter

My function isn't giving me the right output, and it doesn't want to work. I keep getting this error:
TypeError: list indices must be integers, not str
This is my code:
def showShop(level = level, cash = cash):
top = Tkinter.Tk()
shop = ["$100 & level 2 - Shotgun", "$250 & level 3 - 5 Grenades", "$500 & level 5 - Rocket Launcher"]
buttons = []
for i in shop:
temp = shop[i]
temp = Tkinter.Button(top, height=10, width=100, text = temp, command = shopping(i))
temp.pack()
buttons.append(temp)
top.mainloop()
I want it to display what is in the shop list based on what button it is...
Remove temp = shop[i] from the code
for i in shop:
temp = Tkinter.Button(top, height=10, width=100, text = temp, command = shopping(i))
temp.pack()
buttons.append(temp)
The for loop iterates over the elements in the list and not the indices!. The python docs make it more clear
The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence.
Also note that the command argument in the Button constructor takes a function as an argument. So you maybe better off by writing command = shopping there instead of the call command = shopping(i).
Change for i in shop to for i in xrange(shop).
You have to use something like partial to pass arguments to the function called by the button press. Note that you have declared the variable "temp" as 2 different things. The only reason it works is because the second declaration is after you use the first. Also note that the "buttons" list can not be used outside of the function showShop() because it is created in/local to that function. The following is working code based on what you posted. Also, please do not use "i", "l" or "O" as single digit variable names as they can look like numbers.
import Tkinter
from functools import partial
def shopping(btn_num):
print "button number %d pressed" % (btn_num)
buttons[btn_num]["bg"]="lightblue"
def showShop(buttons):
top = Tkinter.Tk()
shop = ["$100 & level 2 - Shotgun", "$250 & level 3 - 5 Grenades",
"$500 & level 5 - Rocket Launcher"]
##buttons = []
for ctr in range(len(shop)):
temp = Tkinter.Button(top, height=10, width=100, text = shop[ctr],
command = partial(shopping, ctr))
temp.pack()
buttons.append(temp)
top.mainloop()
## lists are mutable
buttons=[] ## not local to the function
showShop(buttons)

python class doesn't work for different variable

dear expert i am trying to write a simulation and in my code i have a class like this:
... (some def are here)
class multipole:
global xxp,yyp,zzp,x,y,z,xp,yp,zp,t,tm,h
xxp,yyp,zzp,x,y,z,xp,yp,zp =xxpyypzzp() # some initial values calling
#staticmethod
def quad(f1, f2,f3):
global t,h,mass,ksimax
while t < ksimax:
rk4_two(t,h,mass, f1, f2, f3, xxp, yyp, zzp) # rk function for new xxp, yyp and zzp
t = t + h
tm.append(t)
xp.append(xxp[1])
x.append(xxp[0])
yp.append(yyp[1])
y.append(yyp[0])
zp.append(zzp[1])
z.append(zzp[0])
return xp, x, yp,y,zp,z,tm
if __name__ == "__main__":
qp=multipole()
quxp, qux, quyp,quy,quzp,quz,qutm=qp.quad(0.,0.,0.)
hxp, hx, hyp,hy,hzp,hz,htm =qp.quad(0.022,0.,0.)
oxp, ox, oyp,oy,ozp,oz,otm =qp.quad(-0.023,-0.032,0.0 )
my question is this code only calculate (quxp, qux, quyp,quy,quzp,quz,qutm), but not others (others will turn same value of quxp, qux, quyp,quy,quzp,quz,qutm) could you please tell me why? i am new in python any comments will be appreciated.
Ignoring the fact that this code is... somewhat flawed. I think that the problem is that you are using t which is apparently global but you don't reset it anywhere - so this loop:
while t < ksimax:
...
Will only run once, unless you reset t somewhere. Some pseudo code to explain why this happens:
counter = 0
def do_something():
global counter
print "Starting at", counter
while counter <= 10:
print counter
counter += 5
print "Done"
do_something()
# Starting at 0
# 0
# 5
# 10
# Done
do_something() # Called again, the counter is at 10 now:
# Starting at 10
# Done
As others have mentioned, your code could benefit from some heavy refactoring. Some starting points:
Naming! What does xxpyypzzp even mean? Even if it's obvious to you today, it must be hard to read even for you and unless you have Rainman-like memory you will not understand this next week. Try using descriptive names and if you find yourself adding prefixes or suffixes to variables because you run out of names - think about encapsulating some of this complexity in a class. It seems like the suffixes xp, x, yp, y, zp, z and tm are used a lot. At least create a named tuple to hold these values.
Global variables is generally considered harmful. They make it hard to reason about code - which is why you got this bug in the first place. If you are sprinkling global statements over your code there is time to redesign it. Think about which part of your code should "own" which parts of the state.
Python has a coding standard, called PEP8 - read it and try to follow it.

Basic Functions Help - Python

I'm quite new to Python, and I'm busy trying to figure out how these pesky functions work... The program I'm making is supposed to be working out the area of a triangle, but I can't actually get it to return the local variables to other functions. Any help would be greatly appreciated!
# Area of a triangle
base = 0
height = 0
area = 0
def inData():
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
return base
return height
def triangle(b,h):
area = b / 2 * h
return area
if __name__ == '__main__':
inData()
triangle(base, height)
print "The area of a triangle of base", base, "and height" , height, "will be", area
There are many problems and misconceptions I see in your code; Let me see if I can start from scratch and try to convey the proper way to do these functions for you. In the end, we will have a working version of your code. :)
note: You do not have to declare functions ahead of time in Python-- it does that itself! So no need for base, height, area at the top!
Functions
Functions are in short, sets of commands that get run in a bundle. You know this. What you miss though are the concepts of arguments and parameters and return vs print.
Arguments vs Parameters
When you define a function, you are setting up what you want it to do in the future and at your beck and call. Just like any function f(x) in math, you want one equation that will work with whatever input you give it. For f(x), x is your input.
In programming, this is referred to as a parameter. So when you write in Python:
def Function(x):
y = x*x
return y
You have defined x as your parameter. Now, Arguments are the values that you put into a function, where the parameters go. In Algebra, the applicable idea would be defining a variable. Knowing this, when you actually use that function:
Function(2)
You will get back 4, because you said run Function(x) where x = 2.
This is the concept of Arguments vs Parameters. It is very useful, because you don't always want to ask a user for input inside the function. The more direct your function is, the less it can do. Sometimes you want to use that same function to do math in the background, for example. You can't very well have raw_input() if you expect the process to work on its own in the background, can you?
This is the true value of Arguments vs Parameters.
Return vs Print
In the same vein as not using raw_input() because it is too direct, you want to avoid using print and use return instead. I know you didn't use print here, but you've misunderstood the workings of return and I figure the same lesson applies.
Here is an example: You have two functions.
def Function1(x,y):
z = x*y
print z
def Function2(x,y):
z = x*y
return z
Function 1 prints z, which means that no matter what you want it to do, it will always print z to the console, even if you want it to just do the math.
Meanwhile, Function 2 returns z, meaning it hands back the value of z to the program as it was called. It is also worth noting that as soon as a function hits the line return, it stops running the function further. There is no reason to code beyond this, because the function is no longer being run, unless you had a more advanced code that skipped over return (for example, an if statement).
Why is return so conceptually important?
Because in your original code, you run the function inData(), and after that, not only do you run return twice, but in your if statement, you don't even use what inData returns, you just tell the program to run inData().
When a function returns a value, you have to assign it to something. Take, for instance, simple math in any random programming language. The code:
x = sqrt(4)
print x
will output 2, because at the end of the function sqrt(), it returns its answer. Here, we assigned x to be variable that sqrt(4) gives a return to. While it's true that:
sqrt(4)
will also print 2 to the console, this is because of fool-proofing by language developers, where in fact the language assumes you want the code printed. You're not telling it to do that.
So, when you run the lines of code:
inData()
triangle(base, height)
You are basically saying:
run the function inData()
run the function triangle(base, height)
When, because of their returns, you need to be saying:
set <variable1> equal to the return of inData()
set <variable2> equal to the return of triangle(base,height)
(there is more simplification to be done here, but we'll approach it in a moment).
One last thing on return. In programming, it is useless to write:
x = 1+1
return x
When return 1+1 accomplishes the same thing. Thus, no need to define what the area of a triangle will be and then return the area. Just tell the function to return what it calculates the area to be in the same line of code!
Have I lost you? Still with me? Good!
Simplification of your code
Your code has a few structural problems that, while it may work, would baffle any more seasoned programmer that looked at it. While we're here, why don't we see if I can have you understand what a better practice for this would be.
In your code, you have written (in a summarized form)
variables defined that you don't need
def FunctionThatGathersData()
def FunctionThatDoesTheMath(x,y)
if (condition)
FunctionThatGathersData()
FunctionThatDoesTheMath(x,y)
print out the results
The structure of this would confuse a programmer who has more experience. He might ask the following questions:
What?
Why are you returning things this way?
Why are the variables defined?
Why don't you combine FunctionThatGathersData and FunctionThatDoesTheMath?
Some of these reasons are already exposited upon above, but let's get to the last two questions.
Why are the variables defined?: On one hand, Python handles variables during execution. So you never have to define them ahead of time, but you can, and the advantage of this is as follows:
x = 0
def Function()
x = 5
y = 10
Looking at this code, you might wonder why x is defined. The simple answer is that Python will see that you already have an x, and thus, when you run Function(), you want to overwrite it with the work inside the function. y on the other hand, has no previous definition, and thus a new variable will be created.
However, in your function we don't need any of that because your answer, in its best form, won't need to depend on x outside the function.
Why can't we just combine the two functions together, using what we learned about parameters, arguments, and returns? (hint: we can!)
Here is a new snippet of code that you should now be able to read and understand. Clear your head of what you've read for a moment and see if it makes sense. In it, you will:
Define your function DoTheMathAndThenGiveMeTheValueBack
Decide if __name__ == '__main__'
Provide your values (put them in variables)
Pass those variables as arguments into the function
tell the program to print the base and height and then area based on the function's return.
The Code
def CalculateTriangleArea(b,h):
return b / 2 * h
if __name__ == '__main__':
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
area = CalculateTriangleArea(base,height)
print "The area of a triangle of base", base, "and height", height, "will be", area
If you do not grok this, please, comment and ask me more because I remember struggling with this and know what misunderstandings you are having.
Oh! And I forgot to mention to you what to do about multiple returns.
In the event that you need to return more than one value in a function, you can do so through an array or a tuple. This is just a list of values you have stored. You can access any item in an array or tuple by including the index at the end in the form of [i], where the first item is at [0]. For example:
def Function():
string1 = "nobody"
string2 = "expects"
string3 = "the"
string4 = "spanish"
string5 = "inquisition"
return string1, string2, string3, string4, string5
print Function()[0]
print Function()[1]
print Function()[2]
print Function()[3]
print Function()[4]
print Function() #prints the whole tuple!
Will get you:
nobody
expects
the
spanish
inquisition
('nobody', 'expects', 'the', 'spanish', 'inquisition')
Understand? :)
For more hands-on work in python, try this amazing Python tutorial.
When you do return, the function immediately ends, returning the value. Therefore, your inData function will only return the base, not the height. In addition, you seem to be asking the user to input the base and the height twice -- that's unnecessary, since your inData function already does that
Rather, you want to return two values at the same time by doing something like this. (Note -- I renamed some of your functions for clarity)
# Area of a triangle
def get_user_input():
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
return base, height
def triangle_area(b, h):
area = b / 2 * h
return area
if __name__ == '__main__':
base, height = get_user_input()
area = triangle_area(base, height)
print "The area of a triangle of base", base, "and height" , height, "will be", area
The problems with your code:
# Area of a triangle
base = 0 # You don't need to initialize these values. Even if you want
height = 0 # to make these global you can simple assign inside the if
area = 0 # __name__ == '__main__' condition
def inData():
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
return base # return immediately stops the execution of the function
return height # and returns the value
def triangle(b,h):
area = b / 2 * h
return area
if __name__ == '__main__':
inData() # You are not assigning the returned value to any variable
triangle(base, height)
print "The area of a triangle of base", base, "and height" , height, "will be", area
Correct version of your program:
# Area of a triangle
def inData():
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
return base, height
def triangle(b,h):
area = b / 2 * h
return area
if __name__ == '__main__':
base, height = inData()
area = triangle(base, height)
print "The area of a triangle of base", base, "and height" , height, "will be", area

Categories

Resources