I assigned this variable but it thinks I didn't
Author |
Message |
OREO Speedwagon
|
Posted: Thu Jan 06, 2011 8:59 am Post subject: I assigned this variable but it thinks I didn't |
|
|
My project is a text-based version of a simplified Magic card game for two players. To accomodate the multiplayer functionality, I have to have variables "redirect" to other ones (nowManaField could either == manaField, or manaField2, depending on what player is 'now'). This is working fine for most of the program, but when I try to 'play mana' (move the first card called 'Mana' from nowHand(and therefore hand) to the end nowManaField (which is manaField)), it claims nowManaField was never assigned a value, even when I rearrange the code.
Here is a selected version of my code...
Python: |
running = True
#Define Functions
def playMana(): #put mana into play
if nowManaPlayed != False:
print('You have already played mana this turn.')
else:
x = 0
for i in nowHand:
if nowHand[x] == 'Mana':
nowManaField.append(nowHand[x])
del nowHand[x]
print('You have played Mana.')
break
x += 1
nowManaPlayed = True
#Dictionaries
hand = []
hand2 = []
deck = ['Ghost', 'Witchcraft', 'Mana', 'Soldier', 'Mana', 'Golem', 'Snake', 'Witchcraft', 'Mana', 'Mana']
deck2 = ['Mermaid', 'Seadragon', 'Tidal Wave', 'Mana', 'Mana', 'Mermaid', 'Spirit of Hurricane', 'Tidal Wave', 'Mana', 'Mana']
manaField = []
manaField2 = []
#Set up game
manaPlayed = False
manaPlayed2 = False
hand[0:7] = deck[0:7]
hand2[0:7] = deck2[0:7]
del deck[0:7]
del deck2[0:7]
#Set up for Player One
nowHand = hand
nowManaField = manaField
nowManaPlayed = manaPlayed
#Run loop
while running == True:
command = input('Command? ')
##a bunch of ifs are here...##
elif command == 'play mana':
playMana()
|
Even when I rearrange all the blocks, I still get this error:
Quote: Traceback (most recent call last):
File "H:\PYTHON\Magic_try2.py", line 186, in <module>
playMana()
File "H:\PYTHON\Magic_try2.py", line 34, in playMana
if nowManaPlayed != False:
UnboundLocalError: local variable 'nowManaPlayed' referenced before assignment
How do I clear this? |
|
|
|
|
|
Sponsor Sponsor
|
|
|
rdrake
|
Posted: Thu Jan 06, 2011 9:46 am Post subject: Re: I assigned this variable but it thinks I didn't |
|
|
You're doing sick things. It's trying to warn you.
Essentially you're trying to assign a value to a global variable inside a method. Python thinks you're trying to assign to a local variable that doesn't exist anywhere. You must add the global keyword to make sure it knows what you're doing.
Consult this resource for more details. |
|
|
|
|
|
OREO Speedwagon
|
Posted: Mon Jan 10, 2011 8:58 am Post subject: RE:I assigned this variable but it thinks I didn\'t |
|
|
Thanks rdrake, I applied 'global' liberally and it seems to work now... although I'm a little unclear as to why the global and local distinction even exists. =/
And why is what I'm doing "sick", as you put it? |
|
|
|
|
|
DemonWasp
|
Posted: Mon Jan 10, 2011 10:44 am Post subject: RE:I assigned this variable but it thinks I didn\'t |
|
|
Globals are dangerous, bad programming practice. If you use a global in a method (A), you cannot use it in any method that either calls A, or is called by A. The method is then a leaky abstraction, because the method is "leaking" information about the state of the method. If you use a local in method (A), you can use the same symbol elsewhere without any "collisions".
The most common symptom of this bad practice is variables mysteriously changing value when you least expect it.
Variables should, in general, be in the tightest scope possible. "Scope" means "places where you can refer to that variable". Consider a loop-counter, usually i. That loop counter should only be visible to code within the loop -- and not to methods invoked within that loop, just the code that is directly there. The biggest problem is if that counter is a global, meaning it can be accessed anywhere in the system, for any reason -- this is a huge problem, because one loop will happily stomp all over another's exit condition...pointers will get misplaced, data will get trashed, and buffers will overflow. Bad things will happen.
Generally, you want to use objects to encapsulate "data" with "behaviour". You might want, for example, a class called Deck that describes what a player has in their deck. |
|
|
|
|
|
OREO Speedwagon
|
Posted: Fri Jan 14, 2011 9:26 am Post subject: RE:I assigned this variable but it thinks I didn\'t |
|
|
so, if they're dangerous... should I just revert back to my old code, in which instead of calling functions after testing 'input', just have the code right there? I only changed to functions because I found it easier to read. |
|
|
|
|
|
DemonWasp
|
Posted: Fri Jan 14, 2011 12:21 pm Post subject: RE:I assigned this variable but it thinks I didn\'t |
|
|
No, you should be using functions. However, the functions should reference local variables wherever possible, not global variables. Methods and functions should operate on their parameters (and, if they're members of a class, the contents of that instance of the class).
I don't know Python very well, so forgive syntax errors. Consider (rough, but should give you the idea):
Python: |
def playMana ( manaPlayed, hand, manaField ): #put mana into play
if manaPlayed != False:
print ( 'You have already played mana this turn.' )
return True
else:
x = 0
for i in hand:
if hand[x] == 'Mana':
manaField.append ( nowHand[x] )
del nowHand[x]
print('You have played Mana.')
break
x += 1
return True
return False # fell through the for-loop, so no mana in hand
|
Then you can just call it with one of the following:
Python: |
playMana ( manaPlayed, hand, manaField ) # Player 1
playMana ( manaPlayed2, hand2, manaField2 ) # Player 2
|
|
|
|
|
|
|
OREO Speedwagon
|
Posted: Mon Jan 17, 2011 10:18 am Post subject: RE:I assigned this variable but it thinks I didn\'t |
|
|
OK, thanks, that seems to work
One thing though - are booleans supposed to act weird in this situation?
Python: |
def playMana(manaPlayed, hand, manaField): #put mana into play
if manaPlayed == True:
print('You have already played mana this turn.')
else:
x = 0
for i in hand:
if hand[x] == 'Mana':
manaField.append(hand[x])
del hand[x]
print('You have played Mana.')
manaPlayed = True
break
x += 1
|
I removed the return commands, since with them, no mana was getting moved, ever.
My problem is that manaPlayed, which is used to track whether or not the player has played mana that turn (1 mana per turn), is either not being flipped to 'True' after playing, it's getting re-written somewhere in the code (I've stepped through it and it isn't), or I've somehow got two different copies of manaPlayed and it's checking the wrong one.
Should I make manaPlayed a global? 3: |
|
|
|
|
|
DemonWasp
|
Posted: Mon Jan 17, 2011 1:27 pm Post subject: RE:I assigned this variable but it thinks I didn\'t |
|
|
Sorry, I should have specified: when the function returns something, you're supposed to use that return value. In this case, we're returning a new value of manaPlayed. You would use this like so:
code: |
manaPlayed = playMana ( manaPlayed, hand, manaField ) # Player 1
manaPlayed2 = playMana ( manaPlayed2, hand2, manaField2 ) # Player 2
|
This code could be a lot more idiomatic if each player was represented by a Player object (class), with member method playMana(). In that case, playMana() would take no arguments and return no values - it would operate on the class' member variables, which would include manaPlayed, hand, and manaField. |
|
|
|
|
|
Sponsor Sponsor
|
|
|
OREO Speedwagon
|
Posted: Tue Jan 18, 2011 8:23 am Post subject: RE:I assigned this variable but it thinks I didn\'t |
|
|
Welp, looks like I'm gonna have to learn classes XD
Thanks so much for your help!! |
|
|
|
|
|
|
|