I do not understand why I get a ValueError when I want to transform a calcul string into float. I would like an issue because I am stuck up.
(The aim of my code is to create random equations with increasing level depending on question number.)(I am still a beginner, sorry if my code is unmethodical (and in french too).)
:)
There is my code:
(input)
from random import *
def Numéro_Question():
global NuméroQuestion
NuméroQuestion+=1
print("\t~ Question {} ~\t\n".format(NuméroQuestion))
def Calcul2():
PremierChiffre=randint(0, NuméroQuestion*5+5)
Question=str(PremierChiffre)
for i in range(1,NuméroQuestion+1):
SigneDeCalcul=["+","*","-"]
SigneChoisi=str(choice(SigneDeCalcul))
x=str(randint(0, NuméroQuestion*5+5))
Question=Question+SigneChoisi+x
print(type(Question))
QuestionNumérique=float(QuestionNumérique)
QuestionEcrite=Question+" = "
Question=float
Réponse=input(QuestionEcrite)
NuméroQuestion=0
Raté=0
while Raté<3:
Numéro_Question()
Calcul2()
print("\n\n")
(output)
(The output changes each time you execute the program because it gives random number)
~ Question 1 ~
<class 'str'>
Traceback (most recent call last):
File "main.py", ligne 26, in <module>
Calcul2()
File "mai,.py", ligne 17, in Calcul2
QuestionNumérique=float(QuestionNumérique)
ValueError: could not convert string to float: '3*6'
It's because when you use float(my_string)
it will only work if my_string
can be cast as an actual float. It cannot do the multiplication for you.
Luckily, there is a very useful python function that accepts strings and runs them as code. It is called eval
.
For example, eval("12 + 3")
will return 15
.
Just use eval
instead of float
, like this:
QuestionNumérique=eval(QuestionNumérique)
In summary, you want to "evaluate" (eval
) the Numeric Question, not to "cast" (float
) it.
A caveat: As others point out, eval
is "unsafe". In general, evaluating arbitrary strings as code is unsafe.
UPDATE: I was thinking about this while eating chips earlier and I had a crazy idea.
OK, so, in Python you can execute shell commands in a subprocess and pipe the results. (os.popen
- see here) . Assuming the machine running python has Bash as its shell, we can use Bash's arithmetic expression which (I think) might be easier to safeguard against arbitrary input.
Here is what it would look like:
import os
QuestionNumérique = "117 * 3 + 23 * 3"
shell_command = f"echo $(({QuestionNumérique}))"
piped_shell_result = os.popen(shell_command).read()
stripped_result = piped_shell_result.strip()
result_as_number = float(stripped_result)
This code is still dangerous! You would have to make sure the QuestionNumérique
string contains "globally closed" (
and )
brackets, since someone could easily provide evil input like this:
QuestionNumérique = "117 * 3)); mkdir 'YOU HAVE BEEN H&CK3D'; echo $(("
If you can definitely make sure the input string has properly closed brackets then this should be safer than eval
, since bash arithmetic expression will only do arithmetic.