Why does this script print an extraneous 'none' in the output - python

I've written a simple script to help me better understand using classes. It generates a random character for a game. I defined the object and then call a function on that object that prints out the generated character. At the end of the printed block, there is an extraneous "None" that I'm not sure where it's coming from nor why it's being printed. Here's the sample output:
ted
Strength : 20
Dexterity : 17
Hit Points: 100
Aura : 100
Weapon :
Spell :
Item :
Element :
--------------------
None
In my code, the last line of player.stats() is print "-" * 20 which is displayed right above "None". Here's the code that defines the object:
class Player(object):
def __init__(self, name):
self.name = name
self.strength = randint(15, 20)
self.dexterity = randint(15, 20)
self.hit_points = 100
self.aura = 100
self.weapon = " "
self.spell = " "
self.item = " "
self.element = " "
def stats(self):
print "\n"
print self.name
print "Strength : %d" % self.strength
print "Dexterity : %d" % self.dexterity
print "Hit Points: %d" % self.hit_points
print "Aura : %d" % self.aura
print "Weapon : %s" % self.weapon
print "Spell : %s" % self.spell
print "Item : %s" % self.item
print "Element : %s" % self.element
print "-" * 20
The object is then instanced using this:
name = raw_input("Name your character: ")
player = Player(name)
print player.stats()
The complete code can be read here at Pastebin if necessary.

print player.stats()
Is the culprit. player.stats() == None
You want just:
player.stats()
You'd do better to name your function player.printStats().
Another option would be to make it return a string:
def stats(self):
return '\n'.join([
self.name
"Strength : %d" % self.strength,
"Dexterity : %d" % self.dexterity,
"Hit Points: %d" % self.hit_points,
"Aura : %d" % self.aura,
"Weapon : %s" % self.weapon,
"Spell : %s" % self.spell,
"Item : %s" % self.item,
"Element : %s" % self.element,
"-" * 20
])
And then print player.stats() would behave as expected

The stats() method does not return anything. A function that doesn't return anything evaluates to None. Which is what you print.
So, don't print the return value of the function. Just call it. Now, you should rename the function as printStats() to make it clear what it does. And then just call it like this:
def printStats(self):
....
player = Player(name)
player.printStats()
Naming is a really important part of programming. A slightly poor choice of name often leads to confusion like this.

You print the return value of player.stats():
print player.stats()
but the .stats() method does not have a return statement. The default return value of any function or method in python is None, if no return statement has been given:
>>> def foo():
... pass
...
>>> print foo()
None
Either remove the print before the method call, or have stats() return a string to print instead of doing all the printing in the method.

Related

print(object.method) not printing expected output?

I'm having a foray into OOP in python,
This project is creating some randomly generated RPG characters
The problem I have run into is I am creating a list of these randomly generated characters, and want to print out there stats.
Here is how the characters are randomly generated:
def generateCharacters():
classes = ["B", "E", "W", "D", "K"]
choice = random.choice(classes)
if choice == "B":
return barbarian(70, 20, 50)
elif choice == "E":
return elf(30, 60, 10)
elif choice == "W":
return wizard(50, 70, 30)
elif choice == "D":
return dragon(90, 40, 50)
elif choice == "K":
return knight(60, 10, 60)
and here is the barbarian class, all the other classes are more or less identical:
class barbarian(character):
def __init__(self, charPower, charSAttackPwr, charSpeed):
# Getting the properties from the inheritted character Base Class
character.__init__(self, "B", 100)
self.power = charPower
self.sAttackPwr = charSAttackPwr
self.speed = charSpeed
# Method for getting and returning all the stats of the character
def getStats(self):
# Creating a string to hold all the stats, using concatenation
stats = "Name: %s, Type: %s, Health: %s, Power: %s, Special Attack
Power: %s, Speed: %s" % (self.name, self.type, self.health,
self.power, self.sAttackPwr, self.speed)
# Returns stats to the the function that called
return stats
I've created a method called getStats, which using string concatenation to make a string that shows all the stats:
# Method for getting and returning all the stats of the character
def getStats(self):
# Creating a string to hold all the stats, using concatenation
stats = "Name: %s, Type: %s, Health: %s, Power: %s, Special Attack Power: %s, Speed: %s" % (self.name, self.type, self.health, self.power, self.sAttackPwr, self.speed)
# Returns stats to the the function that called
return stats
When I run the code, it calls main(), which in turn calls menu():
def menu(gameChars):
print("Welcome to the RPG Character Simulator")
print("Here is your randomly generated team: ")
for x in gameChars:
print(x.getStats)
def main():
gameChars = []
for x in range(10):
y = generateCharacters()
gameChars.insert(x, y)
#z = generateCharacters()
menu(gameChars)
#print(z.getStats)
The output I was expecting from the print(x.getStats) would've been, using examples:
Name: bob, Type: barbarian, Health: 100, Power: 70, Special Attack Power: 20, Speed: 20
but instead, I get this:
<bound method barbarian.getStats of <__main__.barbarian object at 0x000001F56A195668>>
What am I missing with this? and how could I get the intended output?
Thanks in advance for any help
Replace this :
print(x.getStats)
With this :
print(x.getStats())
another version would be to use the #property decorator:
class Barbarian(Character):
#property
def getStats(self):
return 'Name: {.name}'.format(self)
which would allow:
bob = Barbarian('bob', …)
print(bob.getStats)
to work as you expect

Return value doesn't work in Python 3 [duplicate]

This question already has answers here:
How do I get a result (output) from a function? How can I use the result later?
(4 answers)
Alternatives for returning multiple values from a Python function [closed]
(14 answers)
Closed 3 years ago.
It seems like I can't pass a value from a function to another even though I have put a return statement in the 1st function.
This is my code:
price=0
TotalPrice=0
def SumPrice(price,TotalPrice):
if cup_cone=="cup":
price=(price+(mass/10)*0.59)*TotalSet
else:
if cone_size=="small":
price=(price+2)*TotalSet
else:
if cone_size=="medium":
price=(price+3)*TotalSet
else:
price=(price+4)*TotalSet
if Member_Ans=="yes":
TotalPrice=TotalPrice+price*0.90
print(price,TotalPrice)
return (price)
return (TotalPrice)
def PrintDetails(price,TotalPrice,Balance):
SumPrice(price,TotalPrice)
if Member_Ans=="yes":
print("Member ID: ", loginID, " (" , Username, ")")
for element in range (len(UserFlavor)):
print (UserFlavor[element], "--- ", UserFlavorPercentage[element], "%")
print ("Total set = ", TotalSet)
print ("Total price = RM %.2f" % (price))
if Member_Ans=="yes":
print ("Price after 10% discount = RM %.2f" % (TotalPrice))
while True:
Payment=int(input("Please enter your payment: "))
if Payment<TotalPrice:
print("Not enough payment.")
if Payment >= TotalPrice:
break
Balance=Balance+(Payment-TotalPrice)
print(Balance)
PrintDetails(price,TotalPrice,Balance)
When I try to print the price and TotalPrice, it prints 0, why?
You are trying to use return twice, which is not allowed (your function will end as soon as it reaches the 1st return statement, making the other one useless).
You can, however, return both values in one statement:
return (price, TotalPrice)
And then assign the value to a tuple or anything else you would like:
my_tuple = SumPrice(a, b)
or
var1, var2 = SumPrice(a, b)
Your second return statement of first function is not reachable! btw try to not use global variables in your code, instead access return values of your first function.
def SumPrice():
price = 0
TotalPrice = 0
if cup_cone=="cup":
price=(price+(mass/10)*0.59)*TotalSet
else:
if cone_size=="small":
price=(price+2)*TotalSet
else:
if cone_size=="medium":
price=(price+3)*TotalSet
else:
price=(price+4)*TotalSet
if Member_Ans=="yes":
TotalPrice=TotalPrice+price*0.90
return price, TotalPrice
def PrintDetails():
price, TotalPrice = SumPrice()
if Member_Ans=="yes":
print("Member ID: ", loginID, " (" , Username, ")")
for element in range (len(UserFlavor)):
print (UserFlavor[element], "--- ", UserFlavorPercentage[element], "%")
print ("Total set = ", TotalSet)
print ("Total price = RM %.2f" % (price))
if Member_Ans=="yes":
print ("Price after 10%% discount = RM %.2f" % (TotalPrice))
while True:
Payment=int(input("Please enter your payment: "))
if Payment<TotalPrice:
print("Not enough payment.")
if Payment >= TotalPrice:
break
Balance=Balance+(Payment-TotalPrice)
print(Balance)
PrintDetails()

Python - Random baby name generator issues - (duplicating input, calling variables)

I've been looking at this all afternoon and can't figure out why the gender input is repeating itself despite only appearing to be called once. It's not part of a loop that I can see either.
I've tried adding variables to act as a counter and tried using an if statement to only run the input if the counter variable is less than 1, but can't figure it out.
Edit: Thanks to the great feedback here, I found out that get_full_name was causing the duplicating gender input in get_first_name - but now I'm running into issues when trying to output the randomly generated first & middle names.
I figured setting the setFirst, setMiddle and setLast variables as globals, but then I get a NameError. I also tried creating a new function to display them, but that wasn't working either. I tried adding "self." (without the quotes) either directly in the function() or one of the indents beneath it.
I'll display the error first, then the full code.
Error:
Traceback (most recent call last):
File "init.py", line 100, in
main()
File "init.py", line 92, in main
print displayName(setFirst, setMiddle, setLast)
NameError: global name 'setFirst' is not defined
I also get name errors trying to concatenate setFirst, setMiddle and setLast into another variable for the full name.
Here's the code:
from os.path import abspath, join, dirname
import random
full_path = lambda filename: abspath(join(dirname(__file__), filename))
FILES = {
'first:male': full_path('dist.male.first'),
'first:female': full_path('dist.female.first'),
'last': full_path('dist.all.last'),
}
def get_name(filename):
selected = random.random() * 90
with open(filename) as name_file:
for line in name_file:
name, _, cummulative, _ = line.split()
if float(cummulative) > selected:
return name
def get_first_name(gender=None):
global determine
global setFirst
print ("First name... Enter 1 for Male, 2 for Female or 3 to be surprised! ")
determine = input()
if determine == 1:
gender = 'male'
if determine == 2:
gender = 'female'
if determine == 3:
print ("You want to be surprised!")
gender = random.choice(('male', 'female'))
return get_name(FILES['first:%s' % gender]).capitalize()
setFirst = get_first_name()
print setFirst + " "
def get_middle_name(gender=None):
global setMiddle
if determine == 1:
gender = 'male'
if determine == 2:
gender = 'female'
if determine == 3:
gender = random.choice(('male', 'female'))
return get_name(FILES['first:%s' % gender]).capitalize()
setMiddle = get_middle_name()
print setMiddle + " "
def get_last_name():
global setLast
#We will implicitly pass a Last Name until other issues are fixed
return “Smith”
setLast = get_last_name()
print setLast
def get_full_name(gender=None):
return u"%s %s %s" % (get_first_name(gender), get_middle_name(gender), get_last_name())
#def displayName(setFirst, setMiddle, setLast):
# print setFirst + " " + setMiddle + " " + setLast
def main():
#print u"%s %s %s" % (setFirst, setMiddle, setLast)
#print displayName(setFirst, setMiddle, setLast)
f = open('output', 'a') #append output to filename output
f.write(get_full_name() + '\n') #and add a line break after each run
f.close()
if __name__ == "__main__":
main()
Even if I try passing the variables to main() like:
def main(setFirst, setMiddle, setLast):
It still gives the NameError about not being defined. What am I doing wrong?
I added this right under "import random", but now I'm getting some rogue "None" displays - which leads me to believe there is a leak in the code somewhere. Thoughts?
setFirst = None
setMiddle = None
setLast = None
Here is the function I created to try to track it:
def displayName(setFirst, setMiddle, setLast):
if setFirst == None:
print ("Random Baby Name Generator")
else:
print setFirst
print setMiddle
print setLast
if setMiddle == None:
print ("Double check the middle name variable.")
if setLast == None:
print ("Double check the last name variable.")
You are calling get_full_name() twice, you need to save the results:
def main():
full_name = get_full_name()
print(full_name)
f = open('output', 'a') #append output to filename output
f.write(full_name + '\n') #and add a line break after each run
f.close()
You also have a few indentation issues as well, plus your use of globals is a bit inefficient. Ideally, functions should do one - and only one - task; this makes them easier to debug.
Try this different version of your code:
from os.path import abspath, join, dirname
import random
full_path = lambda filename: abspath(join(dirname(__file__), filename))
FILES = {
'first:male': full_path('dist.male.first'),
'first:female': full_path('dist.female.first'),
'last': full_path('dist.all.last'),
}
GENDER_MAP = {'1': 'male', '2': 'female'}
def get_gender():
result = input('Select a gender: 1 for Male, 2 for Female or 3 to be surprised')
if result not in ('1', '2', '3'):
print('{} is not a valid choice, please try again'.format(result))
return get_gender()
if result == '3':
return random.choice(('1', '2'))
return result
def get_name(filename):
selected = random.random() * 90
with open(filename) as name_file:
for line in name_file:
name, _, cummulative, _ = line.split()
if float(cummulative) > selected:
return name
def get_name_from_file(name_type='first', gender='male'):
if name_type in ('first','middle',):
name = get_name(FILES['{}:{}'.format(name_type, gender)]).capitalize()
else:
name = get_name(FILES['last']).capitalize()
return name
def get_full_name():
gender = get_gender()
gender_file = GENDER_MAP.get(gender, '')
first_name = get_name_from_file('first', gender_file)
middle_name = get_name_from_file('middle', gender_file)
last_name = get_name_from_file('last')
return '{} {} {}'.format(first_name, middle_name, last_name)
if __name__ == '__main__':
name = get_full_name()
print(full_name)
with open('output', 'a') as f:
f.write('{}\n'.format(full_name))
print('Done')
get_full_name is being called twice, probably, and this result in other functions referenced by get_full_name being called twice as well. Unfortunately this means double input and confusing the user.

How to end a definition of a function?

I have am trying to define a function but I don't know how to end it; it's causing my next function to be in the first function's body. Here's a chunk of the code:
def save(name):
if x['fname'] == 'ply.json':
save1(name)
else: write_data({'fname':'ply.json', 'name':name}, 'ply.json')
def incrace():
race=raw_input()
if race.lower() == "avian":
print "Great %s! So you would like to be an" % (name),
print race.lower(),
print "?"
elif race.lower() == "apex":
print "Great %s! So you would like to be an" % (name),
print race.lower(),
print "?"
elif race.lower() == "human":
print "Great %s! So you would like to be a" % (name),
print race.lower(),
print "?"
elif race.lower() == "floran":
print "Great %s! So you would like to be a" % (name),
print race.lower(),
print "?"
elif race.lower() == "glitch":
print "Great %s! So you would like to be a" % (name),
print race.lower(),
print "?"
elif race.lower() == "hylotl":
print "Great %s! So you would like to be a" % (name),
print race.lower(),
print "?"
else:
print "Sorry, what was that? You're what race?"
incrace()
Here's where I'm having issues:
>>>def save(name):
... if x['fname'] == 'ply.json':
... save1(name)
... else:
... write_data({'fname':'ply.json', 'name':name}, 'ply.json')
...
...def incrace():
File "<stdin>", line 6
def incrace()
^
SyntaxError: invalid syntax
I've been searching for a while but I've no idea how to end the function. I've had the problem previously but how I fixed it I've no idea to either. Thanks in advance.
If you're working in IDLE or the Python shell, hit Enter twice to get back to the >>> prompt, then begin your next function definition.
The only time you wouldn't do this is if you were working on a class definition, in that case you'd leave a single blank line between function defs.
I think you should use Vim editor and run with command..
In my view, I'm confidence with Vim to avoid such kind of errors

Why is this code not correct for PySchools Topic 2 Q uestion 7?

That's my second post in 2 days about pyschools , i hope it's OK.
The exercise asks me to do the following: Write a function that uses a default value.
It also gives me an example code which i have to improve in order to print out the correct output (like if the input is introduce('Lim', 20) , the output should be 'My name is Lim. I am 20 years old.'
The code given by pyschool which i have to improve:
def introduce(name, age = 0):
msg = "My name is %s. " % name
if age == 0:
msg += ""
else:
msg += ""
return msg
My code:
def introduce(name, age=0):
msg = "My name is %s. " % name
if age == 0:
msg += " My age is secret."
else:
msg += " I am %d years old." % age
return msg
It returns the same answers as pyschools' code checker, but due to unclear reasons, the website says my answers are wrong. What might be the problem ?
I'm sorry if i didn't make myself clear enough and you don't understand what i'm trying to say. I have a hard time expressing myself as English is not my native language.
Thank you very much!
Your code is fine. The only thing I can think of is that the output has two spaces in the middle. Try fixing that: msg = "My name is %s." % name
Try this one:
def introduce(name, age=0):
msg = "My name is %s. " % name
if age == 0:
msg += "My age is secret."
else:
msg += "I am %s years old." % age
return msg

Categories