I am currently working on my first program on python, however, when I've encountered a problem concerning the scope of definition of my variables. Here is the problematic sample of my code :
def listen(topLeft, bottomRight):
timeless = 0
# The key combination to check
COMBINATIONS = [
{keyboard.Key.shift, keyboard.KeyCode(char='b')}
]
# The currently active modifiers
current = set()
def execute():
global topLeft,bottomRight,timeless
print("Do Something")
if timeless == 0:
topLeft = mouse.position
timeless += 1
elif timeless == 1:
bottomRight = mouse.position
timeless += 1
elif timeless >= 2:
return False
def on_press(key):
global timeless
if any([key in COMBO for COMBO in COMBINATIONS]):
current.add(key)
if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
execute()
def on_release(key):
if any([key in COMBO for COMBO in COMBINATIONS]):
current.remove(key)
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
Basically, once the Listener calls on_press, execute is called. In order to pass the timeless variable, I use the global tag. However, once the program comes to executing the execute function, I receive the following error code : NameError: name 'timeless' is not defined.
Any help would be appreciated, as I have tried pretty much everything I could
Since timeless is actually a local variable in the function listen, it's not a global variable, and in fact your error comes from the fact that there is no global variable named timeless. What execute needs is to declare timeless (and probably topLeft and bottomRight as well) as nonlocal, so that it refers to the first binding in the stack of containing lexical scopes.
def listen(topLeft, bottomRight):
timeless = 0
# The key combination to check
COMBINATIONS = [
{keyboard.Key.shift, keyboard.KeyCode(char='b')}
]
# The currently active modifiers
current = set()
def execute():
# modify the local variables in listen
nonlocal topLeft,bottomRight,timeless
print("Do Something")
if timeless == 0:
topLeft = mouse.position
timeless += 1
elif timeless == 1:
bottomRight = mouse.position
timeless += 1
elif timeless >= 2:
return False
...
In a function defined at the global scope, global and nonlocal are identical, as the first containing scope is the global scope. In a nested function, global jumps straight to the global scope, while nonlocal walks up the nesting scopes one at a time.
You declare a global variable outside of any function. You can reference a global variable inside a function without using the keyword. You only need to use the keyword global when you are assigning a new value to the variable, sort of as a way of specifying that you want to assign the value to the global variable and not to a new local variable that shares the same name. See this for examples. For your example, first define your globals outside of any function, then use them in the functions, using the global keyword when you want to modify:
# Global variable definitions outside of any function.
timeless = 0
topLeft = 0
bottomRight = 0
# Define the function that uses the variables.
def execute():
print("Do Something")
global timeless
if timeless == 0:
global topLeft # modifying the global variable with this name!
topLeft = mouse.position
timeless += 1
elif timeless == 1:
global bottomRight # modifying the global variable!
bottomRight = mouse.position
timeless += 1
elif timeless >= 2:
return False
All of that said, it's probably best to avoid globals in general. You could define a class instead and use a member property for those things that need to be modified and referenced in multiple methods. For example, something like:
class Listener:
def __init__(self):
self.timeless = 0
self.top_left = 0
self.bottom_right = 0
def execute(self, mouse): # pass some mouse object in, otherwise what's "mouse"?
print('Do something')
if self.timeless == 0:
self.top_left = mouse.position
self.timeless += 1
elif self.timeless == 1:
...
timeless = 0
topLeft = 0
bottomRight = 0
current = set()
def listen(topLeft, bottomRight):
timeless = 0
# The key combination to check
COMBINATIONS = [
{keyboard.Key.shift, keyboard.KeyCode(char='b')}
]
# The currently active modifiers
current = set()
def execute():
print("Do Something")
if timeless == 0:
topLeft = mouse.position
timeless += 1
elif timeless == 1:
bottomRight = mouse.position
timeless += 1
elif timeless >= 2:
return False
def on_press(key):
if any([key in COMBO for COMBO in COMBINATIONS]):
current.add(key)
if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
execute()
def on_release(key):
if any([key in COMBO for COMBO in COMBINATIONS]):
current.remove(key)
Related
i'm using the methode when_motion from the gpiozero library to listen on 3 motion sensor.
for what i understand, this methode permit to callback a fonction when motion is detected while the rest of the programme is running
i'm trying to modify the global variabled i've named state and pickedup to trigger different phase of the programme, to get more control on the overall behaviour.
sensors are triggering sound as expected but the main programme is stuck, never seem to pass the WaitUntil function at the beginning of the main loop
i suspect the state variable not really being global and/or not changing value (but it could be something else
how can i really affect global variable from my method in order for my main programme to go on?
every design suggestion is welcome
here's my code so far:
# a fonction that wait until a condition is fulfill to continue the code
def WaitUntil(condition, output): #defines function
wU = True
while True:
if condition: #checks the condition
output
wU = False
def State(val): #return a global variable without interrupting motion methode
global state
state = val
print("state = {}".format(val))
def Pickedup(val): #return a global variable without interrupting motion methode
global pickedup
pickedup = val
print("pickedup = {}".format(val))
class PIR: # motion sensor object
global state #variables to trigger different phase of the programme
state = 0
global pickedup
pickedup = False
def __init__(self, pin, element):
self.pir = MotionSensor(pin=pin)
self.pir.when_motion = self.motion
self.element = element
self.state = state
self.pickedup = pickedup
def motion(self):
global state
global pickedup
if state == 3: #this is for not playing a sound when you juste put back the object in its jar
self.pir.wait_for_no_motion()
sleep(2)
print("object is back")
State(0)
elif state == 0:
sa.stop_all() #stop alredy playing sound
wave_obj = sa.WaveObject.from_wave_file("{}.wav".format(self.element)) #play the sound associated with this sensor when you pick an object from the associated jar
wave_obj.play()
sleep(5)
print ("objet {} is picked".format(self.element))
Pickedup(True) #wait and consider that the object is picked
WaitUntil(state == 2,FadeOut(0.5)) #wait for programme to reach state 2 and fading out the current playing sound
pir1 = PIR(17,"feu")
pir2 = PIR(27,"eau")
pir3 = PIR(22,"vent")
while True: #from here is the start of the continuous programme
WaitUntil(pickedup == True, print("pick an object")) #here is the problem, cant seem to pass to the next line from here
print("put object in the box")
while cardcount == 0 and pickedup == True:
cards = PN5180().inventory()
cardcount = len(cards)
print(f"{len(cards)} card(s) detected: {' - '.join(cards)}")
#code continue
how can I make this function working? Is there a good subsitute for global??
position=0
score=0
eggY=300
eggX=0
def egglg():
while True:
global eggX
global eggY
if eggX<330:
eggX+=5
eggY+=0.8
elif eggX>=330:
eggY=eggY+2
if eggY>450:
terminate()
elif eggY<450 and eggY>350 and position ==1:
score+=1
return
#rest of my code, with chaning position to 1 when i press w
egglg()
somehow it returns 0
Since you want to write to the global variables eggX, eggY and score you've to declare all 3 variables global:
position=0
score=0
eggY=300
eggX=0
def egglg():
global eggX, eggY, score
# [...]
Note, the variable position is just read, so there is no necessity to declare it golabal.
I send this code through a program to decide which mobs the user will be fighting, but every time it gets to this it produces "Headless_Horseman (or whichever mob it picks) is undefined." I cannot figure out how to 'define' the name.
def mob_picker_randmob1 ():
global Zombie
global Zambie
global Giant_Worm
global Headless_Horseman
global Skeleton
global Ghost
global Ghoul
global Baby_Sister
global Little_Sister
global Big_Sister
randmob1=random.randint(1,5)
if randmob1 == 1:
randmob1 = Zombie
mob_picker_randmob2 ()
elif randmob1 == 2:
randmob1 = Skeleton
mob_picker_randmob2 ()
elif randmob1 == 3:
randmob1 = Giant_Worm
mob_picker_randmob2 ()
elif randmob1 == 4:
randmob1 = Headless_Horseman
mob_picker_randmob2 ()
elif randmob1 == 5:
randmob1 = Zambie
mob_picker_randmob2 ()
you will need to assign values to the variables in your main function, since you are declaring these as global variables.
Zombie = 'zombie'
Zambie = 'zAmbie'
Giant_Worm = 'big worm'
Headless_Horseman = 'horseman without head'
Also, consider using random.choice()
choices = (
Zombie, Zambie, Giant_Worm, Headless_Horseman, Skeleton,
Ghost, Ghoul, Baby_Sister, Little_Sister, Big_Sister,
)
return random.choice(choices)
creates variable sin order for me to recall them later.
def initialise():
global num
global neg
global pos
global pos_list
global neg_list
global pos_sum
global neg_sum
pos_sum=0
neg_sum=0
num=1
neg=0
pos=0
pos_list=[]
neg_list=[]
print("type your numbers")
listing()
Allows the user to repeatedly list positive or negative numbers until they use '0'
def listing():
global num
global neg
global pos
global pos_list
global neg_list
global neg_sum
global pos_sum
num=1
try:
num=float(input())
float(num)
if num<0:
neg_list.append(num)
neg+=1
neg_sum+=num
listing()
elif num>0:
pos_list.append(num)
pos+=1
pos_sum+=um
listing()
else:
end()
except ValueError:
listing()
this ends the code and creates a simple table for the user to view.(I always make tables like this as I find it easier this way and I know there are table functions but I am at school and they do not have the necessary libraries
def end():
global pos_list
global neg_list
global neg_sum
global pos_sum
global neg
global pos
pos_list=pos_list.sort()
neg_list=neg_list.sort()
total_sum=pos_sum+neg_sum
print(" "*33,"Positive"," "*(50-len('positive')),"Negetive"," "*(50-len('negetive')))
i1=0
i2=0
if len(pos_list)>=len(neg_list):
count=len(pos_list)
elif len(pos_list)<len(neg_list):
count=len(neg_list)
else:
pass
for x in range(count):
print("number"," "*(50-len('number')-len(count)),pos_list[i1]," "*(50-len(pos_list[i1])),neg_list[i2]," "*(50-len(neg_list[i2])))
i1+=1
i2+=1
print("amount of numbers"," "*(50-len('amount of numbers')),pos," "*(50-len(pos)),neg," "*50-len(neg))
print("total"," "*(50-len('total')),pos_sum," "*(50-len(pos_sum)),neg_sum," "*(50-len(neg_sum)))
initialise()
the problem:
NameError: global name 'pos_list' is not defined
occurs here:
if len(pos_list)>=len(neg_list):
but I can see this happening 3-4 lines after as well.
I wanted to create a x-y coordinate system even though this is supposed to be a text RPG as to keep track of where everything is. So, I was experimenting on making a function and test for that function that would let the character move on a x-y grid, however, no matter what I try, I cannot make it work. Here is the code:
class Player:
def movement(charactor_movement):
proceed = 0
if charactor_movement == "left":
character.position_x = character.position_x - 1
proceed = 1
elif charactor_movement == "right":
character.position_x = character.position_x + 1
proceed = 1
elif charactor_movement == "forward":
character.position_y = character.position_y + 1
proceed = 1
elif charactor_movement == "backward" or charactor_movement == "back":
character.position_y = character.position_y - 1
proceed = 1
charactor = Player()
charactor.position_x = 0
charactor.position_y = 0
proceed = 0
while proceed == 0:
print "You are at",
print charactor.position_x,
print"x and",
print charactor.position_y,
print"y."
global charactor_movement
charactor_movement = raw_input("Where are you going?")
charactor.movement()
At this point, it does what it is supposed to do up to changing the coordinates, as it prints "You are at 0 x and 0 y" and "Where are you going?" no matter what I type. I have tried adding an else to the function which it defaulted to no matter what I typed and gave me "Sorry, I cannot understand you." Any comments on fixing or generally improving the code would be appreciated.(Note: For the testing I purposely did not add a way to exit. The class is what i need fixed.)
You are getting the same coordinates with each iteration because your values within your while loop are not changing. Incrementing character.position_x within movement will never change the value of character.position_x within your while loop, as it is outside your function's scope. You have to use the global keyword within your movement function for each variable you are changing should you want your current logic to remain the same. Additionally, why not just pass charactor_movement as a parameter to your movement function, as opposed to using global as you currently are doing.
A minimal example:
Consider the following:
def somefunct(x):
mycode = x
mycode = 'no codez'
while True:
print mycode
codez = raw_input('gimme teh codez: ')
somefunct(codez)
which outputs
>>>[evaluate untitled-1.py]
no codez
gimme teh codez: codez!
no codez
Declaring mycode as global in the function places it in the scope of the while loop when assigned, thus
def somefunct(x):
global mycode #make variable global here
mycode = x
mycode = 'no codez'
while True:
print mycode
codez = raw_input('gimme teh codez: ')
somefunct(codez)
results in the output
>>>[evaluate untitled-1.py]
no codez
gimme teh codez: codez!
codez!