I am completely new to python and programming but I am trying to learn it using more practical approach.
What I am trying to do is an exercise for converting different units, e.g. pounds -> kilograms, foot -> meter etc.
I have defined all the functions for different unit pairs:
def kg_to_g(value):
return round(value*1000.0,2)
def g_to_kg(value):
return round(value/1000.0,2)
def inch_to_cm(value):
return round(value*2.54,2)
def cm_to_inch(value):
return round(value/2.54,2)
def ft_to_cm(value):
return round(value*30.48,2)
etc.
and created a list with names of these functions:
unit_list = ['kg_to_g','g_to_kg','inch_to_cm','cm_to_inch',
'ft_to_cm','cm_to_ft','yard_to_m','m_to_yard',
'mile_to_km','km_to_mile','oz_to_g','g_to_oz',
'pound_to_kg','kg_to_pound','stone_to_kg','kg_to_stone',
'pint_to_l','l_to_pint','quart_to_l','l_to_quart',
'gal_to_l','l_to_gal','bar_to_l','l_to_bar']
The program should randomly choose a unit pair(e.g. kg->pounds) and value (e.g. 134.23), and the user will be asked to convert those values.
random_unit = random.choice(unit_list)
lower = 0.1001
upper = 2000.1001
range_width = upper - lower
ranval = round(random.random() * range_width + lower, 2)
When user enters answer, the program should compare answer with the calculations defined by function and tell user if it is a correct answer or wrong answer:
def input_handler(answer):
if answer == random_unit(ranval):
label2.set_text("Correct!")
else:
label2.set_text("Wrong!")
Unfortunately, that way program doesn't work, and codesculptor(codesculptor.org) returns with an error
TypeError: 'str' object is not callable
Could someone please explain to me what is wrong with the code and suggest something to solve the problem.
Because you've enclosed the function names (in the list) in quotes, they have become strings.
Change your list to:
unit_list = [kg_to_g, g_to_kg, inch_to_cm, cm_to_inch,
ft_to_cm, cm_to_ft, yard_to_m, m_to_yard,
mile_to_km, km_to_mile, oz_to_g, g_to_oz,
pound_to_kg, kg_to_pound, stone_to_kg, kg_to_stone,
pint_to_l, l_to_pint, quart_to_l, l_to_quart,
gal_to_l, l_to_gal, bar_to_l, l_to_bar]
And now it is a list of functions, which can be called like this: unit_list[0](34), for example.
So now random_unit(ranval) should not throw an exception.
Note also that comparing floats (if answer == random_unit(ranval)) will most likely cause you problems. See Is floating point math broken? for some detailed explanations of why this is.
As you are rounding you may get away with it, but it's good to be aware of this and understand that you need to deal with it in your code.
I think this is what you are asking about. You should be able to store the functions in a list like this
unit_list = [kg_to_g, g_to_kg, inch_to_cm, cm_to_inch, ft_to_cm]
You can then call each item in the list and give it a parameter and it should execute the function for example like this:
unit_list[0](value)
Related
I'm trying to use a pen-and-paper RPG system I know as a springboard for learning Python. I want to be able to use an object to represent a character, with all the stats that implies. I'm trying to use for and while loops to do things like determine number of actions per turn (based on individual speed) and the actions they take. My problem is that I can't figure out how to refer to the object within the loop so that Python goes through and sequentially affects each of the objects the way I'd want.
class char:
counter = 0 #char counter to keep track of the nbr of doodz
Asidecounter = 0
Bsidecounter = 0
def __init__(self,name,side,Spd,cSPD,DEF,HP,cHP):
self.name=name
self.side=side
self.Spd=Spd
self.cSPD=cSPD
self.DEF=DEF
self.HP=HP
self.cHP=cHP
char.counter+=1
if self.side == "a":
char.Asidecounter+=1
else:
char.Bsidecounter+=1
activechars.append(name)
activechars=[]
defeatedchars=[]
Okay, this gives us a character and some stats. (I tried to omit some extra stats here.) I have a counter for which side they're on, a total character count and so on every time I add a character to the mix. The problem is, then I want to determine the total # of moves available to be distributed among however many characters, I try to do something like this and it just doesn't work for me:
movecount=0
for i in range(len(activechars)):
movepick = activechars[i]
movecount+=movepick.Spd
You can see where I'm going here. I'd like to do something similar for attacks, special powers usage, whatever--put it in a loop but then call (and change) object-specific values from inside the loops, and I just don't know how to.
I've tried this with dictionaries instead of defined "char" objects; e.g.
hero={"Spd":4,"cSPD":4,"DEF":8,"HP":10,"cHP":10}
...and then rewrite the loops for a dictionary instead. But it's not working either way.
(Also, I've been told that I don't follow Python capitalization conventions, for which I apologize.)
You're so close, it appears to be a small issue. Running your code and created char objects, I noticed you're saving the object's name attribute only into the list - for instance, "lancelot" instead of something like <__main__.char at 0x1e5770a9f48>. Simply change the last line to append self instead of name (also check indentation).
class char:
counter = 0 #char counter to keep track of the nbr of doodz
Asidecounter = 0
Bsidecounter = 0
def __init__(self,name,side,Spd,cSPD,DEF,HP,cHP):
self.name=name
self.side=side
self.Spd=Spd
self.cSPD=cSPD
self.DEF=DEF
self.HP=HP
self.cHP=cHP
char.counter+=1
if self.side == "a":
char.Asidecounter+=1
else:
char.Bsidecounter+=1
activechars.append(self)
activechars=[]
defeatedchars=[]
I'm trying to write a small program in python that involves(among other things) Newton method, but i'm encountering several problems, that are probably pretty basic, but since I'm new at programming, i cant overcome..
First i defined the function and it's derivative:
import math
def f(x,e,m):
return x-e*math.sin(x)-m
def df(x,e):
return 1-e*math.cos(x)
def newtons_method(E0,m,e,q):#q is the error
while abs(f(E0,e,m))>q:
E=E0-f(E0,e,m)/df(E0,e)
E0=E
return (E0)
def trueanomaly(e,E):
ta=2*math.arctan(math.sqrt((1+e)/(1-e))*math.tan(E))
return (ta)
def keplerianfunction(T,P,e,K,y,w):
for t in frange (0,100,0.5):
m=(2*math.pi*((t-T)/P))
E0=m+e*math.sin(m)+((e**2)/2)*math.sin(2*m)
newtons_method(E0,m,e,0.001)
trueanomaly(e,E0)
rv=y+K*(e*math.cos(w)+math.cos(w+ta))
return (ta)","(rv)
def frange(start, stop, step):
i = start
while i < stop:
yield i
i += step
The question is that this keeps giving me errors, indentation errors and stuff, especially in the keplerianfunction ... Can someone help me? what am I doing wrong here?
Thank you in advance!
Many things are wrong with this code, and I don't know what the desired behaviour is so can't guarantee that this will help, but I'm going to try and help you debug (although it looks like you mostly need to re-read your Python coursebook...).
First, in most languages if not all, there is a thing called the scope: a variable, function, or any other object, exists only within a certain scope. In particular, variables exist only in the scope of the function that they are defined in. This means that, to use the result of a function, you first need to return that result (which you are doing), and when you call that function you need to store that result into a variable, for example ta = trueanomaly(e, E0).
Then, you don't really need to use brackets when returning values, even if you want to return multiple values. If you do want to return multiple values though, you just need to separate them with a comma, but not with a string character of a comma: write return ta, rv instead of return ta","rv.
Finally, you seem to be iterating over a range of values, yet you don't return the whole range of values but either the first value (if your return is in the for loop), or the last one (if your return is under the for loop). Instead, you may want to store all the ta and rv values into one/two lists, and return that/those lists in the end, for example:
def keplerianfunction(T,P,e,K,y,w):
# Initialise two empty lists
tas = []
rvs = []
for t in frange (0,100,0.5):
m = 2*math.pi*((t-T)/P)
E0 = m+e*math.sin(m)+((e**2)/2)*math.sin(2*m)
E0 = newtons_method(E0,m,e,0.001)
ta = trueanomaly(e,E0)
rv = y+K*(e*math.cos(w)+math.cos(w+ta))
# At each step save the value for ta and rv into the appropriate list
tas.append(ta)
rvs.append(rv)
# And finally return the lists
return (tas,rvs)
Also, why using a new frange function when range has the exact same behaviour and is probably more efficient?
This question was already asked, but I wish to ask something subtly different.
How do we determine if a python function returns multiple values, without calling the function? Is there some way to find out at something more like compile-time instead of at run-time? (I realize that python is an interpreted language)
The following is out of the question:
r = demo_function(data) # takes more than 5 minutes to run
if (not len(r) == 2) or (not isinstance(r, tuple)):
raise ValueError("I was supposed to return EXACTLY two things")
So is:
try:
i, j = demo_function(data)
# I throw TypeError: 'int' object is not iterable
except ValueError:
raise ValueError("Hey! I was expecting two values.")
except TypeError:
s1 = "Hey! I was expecting two values."
s2 = "Also, TypeError was thrown, not ValueError"
raise ValueError(s1 + s2)
The following sort of works, but is extremely inelegant:
r = demo_function(extremely_pruned_down_toy_data) # runs fast
if len(r) != 2:
raise ValueError("There are supposed to be two outputs")
# Now we run it for real
r = demo_function(data) # takes more than 5 minutes to run
There are tools already in python which do similar things. For example, we can find out if a class object has a certain attribute:
prop_str = 'property'
if not hasattr(obj, prop_str):
raise ValueError("There is no attribute named" + prop_str + " NOOOOoooo! ")
Also, we can find out how many INPUTS a function has:
from inspect import signature
sig = signature(demo_function)
p = sig.parameters
if len(p)) != 2:
raise ValueError("The function is supposed to have 2 inputs, but it has" + str(p))
I basically want the following:
p = nargout(demo_function)
if p != 2:
raise ValueError("The function is supposed to have 2 outputs, but it has" + str(p))
Asking what a function returns is one of the most basic things questions one can ask about a function. It feels really weird that I'm having trouble finding out.
EDIT:
juanpa.arrivillaga wrote,
[...] fundamentally, this points to a deeper, underlying design flaw: why do you have functions that can return different length containers when you are expecting a specific length?
Well, let me explain. I have something like this:
def process_data(data_processor, data):
x, y = data_processor(data)
return x, y
A precondition of the process_data function is that the input data_processor MUST return two items. As such, I want to write some error checking code to enforce the precondition.
def process_data(data_processor, data):
# make sure data_processor returns exactly two things!
verify_data_processor(data_processor)
x, y = data_processor(data)
return x, y
However, it looks like that's not easily doable.
A function really only has a single return value. It can return a container, such as a tuple, of whatever length. But there is no inherent way for a Python function to know the length of such a value, Python is much too dynamic. Indeed, in general, the interpreter does not know the nature of the return value of a function. But even if we stick to just considering functions that return containers, consider the following function:
def howmany(n):
return n*('foo',)
Well, what should nargout(howmany) return?
And python does not special case something like return x, y, nor should it, because then what should be the behavior when the length of the returned container is indeterminate, such as return n*(1,)? No, it is up to the caller to deal with the case of a function returning a container, in one of the ways you've already illustrated.
And fundamentally, this points to a deeper, underlying design flaw: why do you have functions that can return different length containers when you are expecting a specific length?
Relatively new to programming and doing some coursework on python. I've been told to label all my variables with the correct data type. For example an integer would be called iVariable and a string would be sString. Although I recall someone telling me that sometimes you need to label a variable containing a number a string? I don't really understand what they meant by this. Below is the start of my code, it's not perfect but if someone could tell me if I've done the data types right or wrong and told me what their supposed to be that would be great. Thanks in advance
iResultlist = 0
sEndScript = 0
while iResultlist == 0:
if sEndScript == "y":
iResultlist = 1
sStudent = input("What is the students name?")
bInputValid = False
while (bInputValid == False):
sUserResponse = input("What score did they get")
if sUserResponse.isdigit():
iScore = int(sUserResponse)
bInputValid = True
else:
print ("Enter a valid number please")
iClass = input("What class is the student in? \"1\, "\"2\" or \"3\"")
if iClass == "1":
Class1 = open("Class1.csv", "a+")
Class1.write(Student+","+Score+"\n")
Class1.close()
Also is there a data type I should use for my file names? And if so what is it?
sometimes you need to label a variable containing a number a string
I'm guessing that what they meant is a situation like in:
iClass = input("What class is the student in? \"1\, "\"2\" or \"3\"")
The content of iClass is going to be a number, sure. But the type is still a string. To get a numerical value out of it, you still have to convert it via int(iClass). So if you're really going for the hungarian notation, then it should be something like:
sClass = input(...) # this is a string, even if the string is "123"
iClass = int(sClass) # now it's a proper int
Although in the current code, you just don't need the converted iClass at all.
If you're not sure what type something is at some point, you can always print it out during execution, like:
print("iClass is:", type(iClass))
But like #Blorgbeard commented - hungarian notation isn't really popular outside of winapi these days.
You can always test the type of a variable by doing
if isinstance(iClass, int):
... # continue with you example
Instead of 'int' you can use other types like str, float etc
BTW, the Hungarian notation is useful in languages that enforce a variable to only have one type. It was common in the first language I learnt, FORTRAN, but punched cards were the thing too.
every time the below code runs, it goes straight through to the first else statement, then runs the next else statement four times. what is going on and how do I fix it so it calls the movement() module?
class square(object):
def __init__(self,updown,leftright,residence,name):
self.updown = updown
self.leftright = leftright
self.residence = bool
self.name = name
a1 = square(1,1,True,"a1")
a2 = square(2,1,False,"a2")
b1 = square(1,2,False,"b1")
b2 = square(2,2,False,"b2")
square_dict = {a1:"a1",a2:"a2",b1:"b1",b2:"b2"}
movement_select()
def movement_select():
response = raw_input("where would you like to move?")
if response in square_dict:
moveTo = square_dict[response]
else:
print "this runs once"
for a in square_dict:
if a.residence == True:
moveFrom = a
movement(moveFrom,moveTo)
else:
print "this runs four times"
movement_select()
Look at how you're defining residence:
self.residence = bool
So, for any square a, a.residence will be the type bool, never the boolean value True (or anything else). So this test will always fail:
if a.residence == True:
To fix it, change that first line to:
self.residence = residence
While we're at it, you rarely need == True, so you can also change the second line to:
if a.residence:
But that isn't a necessary fix, just a way of simplifying your code a bit.
Meanwhile, your squares_dict is a bit odd. I'm not sure whether it's incorrect or not, but let's take a look:
It maps from square objects to their names. That could be a useful thing to do. It means you can iterate over the dict and get all the squares—as you correctly do in your code. And if you later had a square and wanted to get its name, you could use square_dict for that. Then again, you could probably get the same benefit with just a square_list, and using the name already available as an attribute of the square objects (unless you need the same square to have different names in different contexts).
And meanwhile, a mapping in this direction can't be used for looking up squares_dict[response], because response is a name, not a square. So, you definitely need a mapping in the opposite direction, either in addition to or instead of this one.
If you scrap the square-to-name mapping and only keep the name-to-square mapping, you can still iterate over the squares; you'd just have to do for square in squares_dict.values(): instead of just for square in squares_dict:.
First problem: your dictionary appears to be backwards: you want to look up the square objects from their locations, rather than the other way around. This is why your first conditional is never true. You also might as well strip() the response to ensure that you don't have any hidden whitespace in there.
square_dict = {"a1":a1, "a2":a2, "b1":b1, "b2":b2}
# Later...
response = raw_input("where would you like to move?").strip()
# Later still...
for a in square_dict.values(): # Because we switched the dictionary around!
If you don't want to silently strip off the whitespace, I'd suggest that you at least echo their input back to them (print('"{}"'.format(response))) in the case that it's not found in your dictionary, so they (you) can be sure that at least the input was correct.
The second problem is because of how you define residence. You set the variable equal to bool, which is not what you want at all. Line five ought to read:
self.residence = residence
Finally, some other thoughts on your code! You check whether a value is True by checking if a.residence == True:. The preferred form of this comparison is the simpler version:
if a.residence:
Your methods could also be named more descriptively. Generally speaking, it's always nice to begin a function or method name with a verb, to improve readability. This is of course a question of style, but for instance, the two functions we see, movement_select and movement aren't extremely clear as to their function. It would be much easier to read if they used a standardized form, e.g. choose_move and perform_move.
self.residence = bool
should be
self.residence = residence
You don´t set residence right, this is wrong:
class square(object):
def __init__(self,updown,leftright,residence,name):
self.updown = updown
self.leftright = leftright
self.residence = bool
self.name = name
it has to be
class square(object):
def __init__(self,updown,leftright,residence,name):
self.updown = updown
self.leftright = leftright
self.residence = residence # not bool!!
self.name = name
Your response contains \n symbol, just strip() it
You should also swap places between keys and values in your dictionary