How do I get my go function to work properly? - python

trying to make a text adventure here. I was setting up the actions module, and testing out the movements when the code keeps telling me my functions are not defined even though I defined them in the code itself (wouldn't recognize it in the player module) I am stuck, any ideas?
Error:
go_north(self)
NameError: name 'go_north' is not defined
Code:
def go(self, dx, dy):
self.location_x += dx
self.location_y += dy
print(world.tile_exists(self.location_x, self.location_y).intro_text())
def go_north(self):
self.go(dx=0, dy=-1)
def go_south(self):
self.go(dx=0, dy=1)
def go_east(self):
self.go(dx=1, dy=0)
def go_west(self):
self.go(dx=-1, dy=0)
game = "play"
while game == "play":
x = input()
y = " is not a valid command"
string = x + y
if x == "go north":
go_north(self)
if x == "go south":
go_south(self)
if x == "go east":
go_east(self)
if x == "go west":
go_west(self)
else:
print(string)

Try self.go_north() instead of go_north(self)

Kunal Katiyar is right, but also don't forget to list all functions(define them) before calling any, i had an error and struggled for 30 minutes because a function i called earlier in the code was defined later!

Common mistake from python beginners - A function defined in a class is not global.
You first to initialize a "go" instance:
var_name = go()
Then call the function by its variable name:
var_name.go_north()
Also, "self" does not need to be passed into the function when calling it.
In addition, when calling a class function inside of the class, call it using self:
self.whatever()
To be able to pass variables into a class function, simply do it as normal, but remember (when calling it) to exclude the "self"!

You could make the function a global so it is accessible

Related

How to print actual name of variable class type in function?

I'm trying to return variable name, but i keep getting this:
<classes.man.man object at (some numbers (as example:0x03BDCA50))>
Below is my code:
from classes.man import man
def competition(guy1, guy2, counter1=0, counter2=0):
.......................
some *ok* manipulations
.......................
if counter1>counter2:
return guy1
bob = man(172, 'green')
bib = man(190, 'brown')
print(competition(bob , bib ))
Epilogue
If anyone want to, explain please what I can write instead of __class__ in example below to get variable name.
def __repr__(self):
return self.__class__.__name__
Anyway, thank you for all of your support
There are different ways to approach your problem.
The simplest I can fathom is if you can change the class man, make it accept an optional name in its __init__ and store it in the instance. This should look like this:
class man:
def __init__(number, color, name="John Doe"):
self.name = name
# rest of your code here
That way in your function you could just do with:
return guy1.name
Additionnally, if you want to go an extra step, you could define a __str__ method in your class man so that when you pass it to str() or print(), it shows the name instead:
# Inside class man
def __str__(self):
return self.name
That way your function could just do:
return guy1
And when you print the return value of your function it actually prints the name.
If you cannot alter class man, here is an extremely convoluted and costly suggestion, that could probably break depending on context:
import inspect
def competition(guy1, guy2, counter1=0, counter2=0):
guy1_name = ""
guy2_name = ""
for name, value in inspect.stack()[-1].frame.f_locals.items():
if value is guy1:
guy1_name = name
elif value is guy2:
guy2_name = name
if counter1 > counter2:
return guy1_name
elif counter2 > counter2:
return guy1_name
else:
return "Noone"
Valentin's answer - the first part of it at least (adding a name attribute to man) - is of course the proper, obvious solution.
Now wrt/ the second part (the inspect.stack hack), it's brittle at best - the "variables names" we're interested in might not necessarily be defined in the first parent frame, and FWIW they could as well just come from a dict etc...
Also, it's definitly not the competition() function's responsability to care about this (don't mix domain layer with presentation layer, thanks), and it's totally useless since the caller code can easily solve this part by itself:
def competition(guy1, guy2, counter1=0, counter2=0):
.......................
some *ok* manipulations
.......................
if counter1>counter2:
return guy1
def main():
bob = man(172, 'green')
bib = man(190, 'brown')
winner = competition(bob, bib)
if winner is bob:
print("bob wins")
elif winner is bib:
print("bib wins")
else:
print("tie!")
Python prints the location of class objects in memory if they are passed to the print() function as default. If you want a prettier output for a class you need to define the __repr__(self) function for that class which should return a string that is printed if an object is passed to print(). Then you can just return guy1
__repr__ is the method that defines the name in your case.
By default it gives you the object type information. If you want to print more apt name then you should override the __repr__ method
Check below code for instance
class class_with_overrided_repr:
def __repr__(self):
return "class_with_overrided_repr"
class class_without_overrided_repr:
pass
x = class_with_overrided_repr()
print x # class_with_overrided_repr
x = class_without_overrided_repr()
print x # <__main__.class_without_overrided_repr instance at 0x7f06002aa368>
Let me know if this what you want?

Methods using methods in python

I know there are many questions that touch upon this area, but none have clearly answered the problem I'm facing (or perhaps I'm just really thick).
So I'm transferring functional python code to OOP python, and I have some code
class fake_class:
def __init__(self, data_type=None):
if data_type is None:
self.data_type = ""
else:
self.data_type = data_type
def printToLog(x='', *args):
if args:
x = x.format(*args)
else:
x = str(x)
logFile.write(x)
logFile.write('\n')
print(x)
if __name__ == '__main__':
main()
def main(self):
self.printToLog('this is just an example, for some fake code')
f = fake_class('data-xml-435')
# please appreciate that the full code is over 500 lines
# long that has been edited down for the sake of readability
I need the main method to be able to call other methods in the class, but no matter what I do, I cannot manage to allow it to do so. I have made printToLog into a classmethod, I have tried different ways of instantiating the fake_class, calling and all to no avail. The program complains that it doesn't know what printToLog is, what self is or what fake_class is!
So how might I call a method with another method within Python?
if __name__ == '__main__':
main()
does not make any sense with class. You just don't need them.
With that removed, you have to call main explicitly using the object you created.
f = fake_class('data-xml-435')
f.main() # or f.printToLog(with arguments) whichever is exciting you!
Again, printToLog is function of class, so you need a self:
def printToLog(self, x='', *args):
if args:
x = x.format(*args)
else:
x = str(x)
logFile.write(x)
logFile.write('\n')
print(x)

How can I use an 'update' function to 'open' and update if the object is not yet open?

My example is a progress bar
In its simplest form a progress bar is
bar = ProgressBar.Open()
for item in list:
bar.Update(count, len(list))
I would instead like my calling code to be
for item in list:
bar.Update(count, len(list))
I want my Update() function to Open() a bar for the caller if one is not open. The caller doesn't need any other access to the bar than to update it so there's no value in having the meter` handle.
How can I retain state to tell if the Update had been previously called?
I could create a global variable and keep track that way, but I have a gut sense there's a Pythonista way of doing it.
Trying again, but in a way that has no application to stumble on.
The base question is:
I have a function that will be called multiple times.
I want to do something different the first time it is called.
How can a function in Python do that?
In C, that of course would be a...
static variable
I'm just now kinda figuring it out as I type, sorry.
========================
I'm sure all these edits are not how stackoverflow is supposed to work. I'm sorry for not getting it right yet, but am very appreciative of the replies.
Despite it sounding like I'm breaking all the rules of good practices, it's when looked at from the CALLER'S point of view that I had hoped to make an impact.
What if the only thing you needed to do to add a progress meter, even for debugging, to your program was make a call to a progress meter update in the location you want to show progress?
That's the underlying motivation. Slide in 1-line, get something cool for the trouble.
This progress meter was added to my otherwise boring file de-duplicator by adding just the single call:
msg = f'Deduplicating {idx} of {total_files} files\n' f'{dup_count} Dupes found\n' f'{small_count} Too small'
not_cancelled = sGUI.ProgressBar('De-dupe', msg, idx, total_files)
To avoid using global variables, you can use decorator. Here's a simple example:
def open():
print 'open'
def update():
print 'update'
def call_once(func1, *args1, **kwargs1):
def decorator(func2):
called = [False]
def wrapper(*args2 ,**kwargs2):
if not called[0]:
func1(*args1, **kwargs1)
called[0] = True
return func2(*args2, **kwargs2)
return wrapper
return decorator
#call_once(open)
def my_update():
update()
for i in xrange(5):
my_update()
which give the result:
open
update
update
update
update
update
For more information about decorator, please visit: https://wiki.python.org/moin/PythonDecorators
For what you want, you can use a class:
class ProgressBar:
def __init__(self):
self._opened = False
def Open(self):
print("Open")
def Update(self):
if self._opened:
print("Update!")
else:
self.Open()
print("set flag")
self._opened = True
print("Update")
In action:
In [32]: bar = ProgressBar()
In [33]: bar.Update()
Open
set flag
Update
In [34]: bar.Update()
Update!
Note: I copied your casing so as to make it more clear to you, however, the official Python style would be like this:
class ProgressBar:
def __init__(self):
self._opened = False
def open(self):
pass # open stuff
def update(self):
if self._opened:
pass # update stuff
else:
self.open()
self._opened = True
Using snake_case for everything except the ClassName.
OK, I found a solution using 'globals'. I thought that a nested function was the way to do it... then I mixed the two.
By 'globals' I meant variables declared outside the scope of a function. I want to be able to import my module without the import creating anything.
Here's the code that shows how to do this with globals
def my_update(amount):
global flag
if 'flag' in globals():
print('I have been here')
else:
print('I have not been here')
flag = True
return
for i in range(10):
print(f'Calling number {i}')
result = my_update(1)
It does the job for the goals I had set out, but I'm SURE there are better, safer ways that are more elegant as well.
I posted this question on a Python forum and got back the best answer so far using a function attribute. It's brilliant and it works.
Here is code that demonstrates this construct... it should go in everyone's 'Favorite Python Constructs' notebook in my opinion.
def func():
if not hasattr(func, 'static_variable'):
func.static_variable = 0
func.static_variable += 1
return func.static_variable
def main():
for i in range(10):
print('func = {}'.format(func()))
if __name__ == '__main__':
main()
The output is
func = 1
func = 2
func = 3
func = 4
func = 5
func = 6
func = 7
func = 8
func = 9
func = 10

How do I pass variables around in Python?

I want to make a text-based fighting game, but in order to do so I need to use several functions and pass values around such as damage, weapons, and health.
Please allow this code to be able to pass "weapons" "damage" "p1 n p2" throughout my code. As you can see I have tried using parameters for p1 n p2, but I am a little bit a newbie.
import random
def main():
print("Welcome to fight club!\nYou will be fighting next!\nMake sure you have two people ready to play!")
p1=input("\nEnter player 1's name ")
p2=input("Enter player 2's name ")
print("Time to get your weapons for round one!\n")
round1(p1,p2)
def randomweapons(p1,p2):
weapon=["Stick","Baseball bat","Golf club","Cricket bat","Knife",]
p1weapon=random.choice(weapon)
p2weapon=random.choice(weapon)
print(p1 +" has found a "+p1weapon)
print(p2 +" has found a "+p2weapon)
def randomdamage():
damage=["17","13","10","18","15"]
p1damage=random.choice(damage)
p2damage=random.choice(damage)
def round1(p1,p2):
randomweapons(p1,p2)
def round2():
pass
def round3():
pass
def weaponlocation():
pass
main()
There are a few options.
One is to pass the values as parameters and return values from your various functions. You're already doing this with the names of the two players, which are passed as parameters from main to round1 and from there on to randomweapons. You just need to decide what else needs to be passed around.
When the information needs to flow the other direction (from a called function back to the caller), use return. For instance, you might have randomweapons return the weapons it chose to whatever function calls it (with return p1weapon, p2weapon). You could then save the weapons in the calling function by assigning the function's return value to a variable or multiple variables, using Python's tuple-unpacking syntax: w1, w2 = randomweapons(p1, p2). The calling function could do whatever it wants with those variables from then on (including passing them to other functions).
Another, probably better approach is to use object oriented programming. If your functions are methods defined in some class (e.g. MyGame), you can save various pieces of data as attributes on an instance of the class. The methods get the instance passed in automatically as the first parameter, which is conventionally named self. Here's a somewhat crude example of what that could be like:
class MyGame: # define the class
def play(self): # each method gets an instance passed as "self"
self.p1 = input("Enter player 1's name ") # attributes can be assigned on self
self.p2 = input("Enter player 2's name ")
self.round1()
self.round2()
def random_weapons(self):
weapons = ["Stick", "Baseball bat", "Golf club", "Cricket bat", "Knife"]
self.w1 = random.choice(weapons)
self.w2 = random.choice(weapons)
print(self.p1 + " has found a " + self.w1) # and looked up again in other methods
print(self.p2 + " has found a " + self.w2)
def round1(self):
print("Lets pick weapons for Round 1")
self.random_weapons()
def round2(self):
print("Lets pick weapons for Round 2")
self.random_weapons()
def main():
game = MyGame() # create the instance
game.play() # call the play() method on it, to actually start the game

Global variables declared within function are still considered local

I am trying to write the program battleship. I have two gameboard matrices: one for player, one for computer. These are defined outside of main because I want them to be global variables because several functions manipulate/read them. I am using Python 2.6.1.
#create player game board (10x10 matrix filled with zeros)
playerBoard = [[0]*10 for i in range(10)]
#create computer game board (10x10 matrix filled with zeros)
computerBoard = [[0]*10 for i in range(10)]
Then I define the main function.
#define main function
def main():
global playerBoard
global computerBoard
#keepGoing is true
keepGoing = True
#while keepGoing is true
while keepGoing:
#call main menu function. Set to response.
response = mainMenu()
#if response is 1
if response == "1":
#begin new game
#call clearBoards function
clearBoards()
#call resetCounters function
resetCounters()
#call placeShips function (player)
playerBoard = placeShips(playerBoard, "player")
#call placeShips function (computer)
computerBoard = placeShips(computerBoard, "computer")
#call guessCycler function
guessCycler()
#if response is 2
if response == "2":
#keepGoing is false
keepGoing = False
Despite my declaration of global playerboard and global computerBoard within main PyScripter still says those are local variables. I don't understand this. How can I make sure they are global?
Documents I have already looked at:
Using global variables in a function other than the one that created them
Changing global variables within a function
http://www.python-course.eu/global_vs_local_variables.php
I definitely think you should reconsider if you need them to be global - You don't .-)
The cheap way, is do declare your stuff and the pass them on as parameters to the function
def MyFunc(board1):
print board1
board1 = "Very weak horse"
MyFunc(board1)
The real way to do it is to create a class and then access them using self
class MySuperClass():
def __init__(self):
self.horse = "No way up"
def myRealCoolFunc(self):
print self.horse
uhhh = MySuperClass()
uhhh.myRealCoolFunc()

Categories