I came across this code and it works, but I am not entirely sure about when to use ast and whether there are performance issues when this is used instead of getting the string value from input() and converting it to int.
import ast
cyper_key = ast.literal_eval(input("Enter the key (a value between 0 and 25) : "))
# this get the user input as an int to the variable cyper_key
I read the docs I understand what it does.
This can be used for safely evaluating strings containing Python
values from untrusted sources without the need to parse the values
oneself. It is not capable of evaluating arbitrarily complex
expressions, for example involving operators or indexing.
I am looking for an explanation on above bold points.
When to use it.
ast.literal_eval(input()) would be useful if you expected a list (or something similar) by the user. For example '[1,2]' would be converted to [1,2].
If the user is supposed to provide a number ast.literal_eval(input()) can be replaced with float(input()), or int(input()) if an integer is expected.
Performance
Note that premature [micro-]optimization is the root of all evil. But since you asked:
To test the speed of ast.literal_eval(input()) and float(input() you can use timeit.
Timing will vary based on the input given by the user.
Ints and floats are valid input, while anything else would be invalid. Giving 50% ints, 40% floats and 10% random as input, float(input()) is x12 faster.
With 10%, 10%, 80% and float(input()) is x6 faster.
import timeit as tt
lst_size = 10**5
# Set the percentages of input tried by user.
percentages = {'ints': .10,
'floats': .10,
'strings': .80}
assert 1 - sum(percentages.values()) < 0.00000001
ints_floats_strings = {k: int(v*lst_size) for k, v in percentages.items()}
setup = """
import ast
def f(x):
try:
float(x)
except:
pass
def g(x):
try:
ast.literal_eval(x)
except:
pass
l = [str(i) for i in range({ints})]
l += [str(float(i)) for i in range({floats})]
l += [']9' for _ in range({strings}//2)] + ['a' for _ in range({strings}//2)]
""".format(**ints_floats_strings)
stmt1 = """
for i in l:
f(i)
"""
stmt2 = """
for i in l:
g(i)
"""
reps = 10**1
t1 = tt.timeit(stmt1, setup, number=reps)
t2 = tt.timeit(stmt2, setup, number=reps)
print(t1)
print(t2)
print(t2/t1)
ast -> Abstract Syntax Trees
ast.literal_eval raises an exception if the input isn't a valid Python datatype, so the code won't be executed if it's not.
This link AST is useful for you to understand ast.
If it's going to be used as an int, then just use:
cypher_key = int(input("Enter the key (a value between 0 and 25) : "))
Only use that if you expect the user to be entering 10e7 or something. If you want to handle different bases, you can use int(input(...), 0) to automatically divine the base. If it really is an integer value between 0 and 25, there's no reason to use ast.
Running this in a python-3.x shell, I get no differences when I give correct input:
>>> cyper_key = ast.literal_eval(input("Enter the key (a value between 0 and 25) : "))
Enter the key (a value between 0 and 25) : 5
>>> cyper_key
5
However, when you give a string or something that cannot be converted, the error can be confusing and/or misleading:
>>> cyper_key = ast.literal_eval(input("Enter the key (a value between 0 and 25) : "))
Enter the key (a value between 0 and 25) : foo
Traceback (most recent call last):
File "python", line 3, in <module>
ValueError: malformed node or string: <_ast.Name object at 0x136c968>
However, this can be useful if you don't want to cast either float or int to your input, which may lead to ValueErrors for your int or floating points for your float.
Thus, I see no necessary use in using ast to parse your input, but it can work as an alternate.
Related
This question already has answers here:
ValueError: invalid literal for int() with base 10: ''
(15 answers)
Closed last month.
I wrote a program to solve y = a^x and then project it on a graph. The problem is that whenever a < 1 I get the error:
ValueError: invalid literal for int () with base 10.
Any suggestions?
Here's the traceback:
Traceback (most recent call last):
File "C:\Users\kasutaja\Desktop\EksponentfunktsioonTEST - koopia.py", line 13, in <module>
if int(a) < 0:
ValueError: invalid literal for int() with base 10: '0.3'
The problem arises every time I put a number that is smaller than one, but larger than 0. For this example it was 0.3 .
This is my code:
# y = a^x
import time
import math
import sys
import os
import subprocess
import matplotlib.pyplot as plt
print ("y = a^x")
print ("")
a = input ("Enter 'a' ")
print ("")
if int(a) < 0:
print ("'a' is negative, no solution")
elif int(a) == 1:
print ("'a' is equal with 1, no solution")
else:
fig = plt.figure ()
x = [-2,-1.75,-1.5,-1.25,-1,-0.75,-0.5,-0.25,0,0.25,0.5,0.75,1,1.25,1.5,1.75,2]
y = [int(a)**(-2),int(a)**(-1.75),int(a)**(-1.5),int(a)**(-1.25),
int(a)**(-1),int(a)**(-0.75),int(a)**(-0.5),int(a)**(-0.25),
int(a)**(0),int(a)**(0.25),int(a)**(0.5),int(a)**(0.75),
int(a)**1,int(a)**(1.25),int(a)**(1.5),int(a)**(1.75), int(a)**(2)]
ax = fig.add_subplot(1,1,1)
ax.set_title('y = a**x')
ax.plot(x,y)
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.spines['left'].set_smart_bounds(True)
ax.spines['bottom'].set_smart_bounds(True)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
plt.savefig("graph.png")
subprocess.Popen('explorer "C:\\Users\\kasutaja\\desktop\\graph.png"')
def restart_program():
python = sys.executable
os.execl(python, python, * sys.argv)
if __name__ == "__main__":
answer = input("Restart program? ")
if answer.strip() in "YES yes Yes y Y".split():
restart_program()
else:
os.remove("C:\\Users\\kasutaja\\desktop\\graph.png")
Answer:
Your traceback is telling you that int() takes integers, you are trying to give a decimal, so you need to use float():
a = float(a)
This should work as expected:
>>> int(input("Type a number: "))
Type a number: 0.3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '0.3'
>>> float(input("Type a number: "))
Type a number: 0.3
0.3
Computers store numbers in a variety of different ways. Python has two main ones. Integers, which store whole numbers (ℤ), and floating point numbers, which store real numbers (ℝ). You need to use the right one based on what you require.
(As a note, Python is pretty good at abstracting this away from you, most other language also have double precision floating point numbers, for instance, but you don't need to worry about that. Since 3.0, Python will also automatically convert integers to floats if you divide them, so it's actually very easy to work with.)
Previous guess at answer before we had the traceback:
Your problem is that whatever you are typing is can't be converted into a number. This could be caused by a lot of things, for example:
>>> int(input("Type a number: "))
Type a number: -1
-1
>>> int(input("Type a number: "))
Type a number: - 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '- 1'
Adding a space between the - and 1 will cause the string not to be parsed correctly into a number. This is, of course, just an example, and you will have to tell us what input you are giving for us to be able to say for sure what the issue is.
Advice on code style:
y = [int(a)**(-2),int(a)**(-1.75),int(a)**(-1.5),int(a)**(-1.25),
int(a)**(-1),int(a)**(-0.75),int(a)**(-0.5),int(a)**(-0.25),
int(a)**(0),int(a)**(0.25),int(a)**(0.5),int(a)**(0.75),
int(a)**1,int(a)**(1.25),int(a)**(1.5),int(a)**(1.75), int(a)**(2)]
This is an example of a really bad coding habit. Where you are copying something again and again something is wrong. Firstly, you use int(a) a ton of times, wherever you do this, you should instead assign the value to a variable, and use that instead, avoiding typing (and forcing the computer to calculate) the value again and again:
a = int(a)
In this example I assign the value back to a, overwriting the old value with the new one we want to use.
y = [a**i for i in x]
This code produces the same result as the monster above, without the masses of writing out the same thing again and again. It's a simple list comprehension. This also means that if you edit x, you don't need to do anything to y, it will naturally update to suit.
Also note that PEP-8, the Python style guide, suggests strongly that you don't leave spaces between an identifier and the brackets when making a function call.
As Lattyware said, there is a difference between Python2 & Python3 that leads to this error:
With Python2, int(str(5/2)) gives you 2.
With Python3, the same gives you: ValueError: invalid literal for int() with base 10: '2.5'
If you need to convert some string that could contain float instead of int, you should always use the following ugly formula:
int(float(myStr))
As float('3.0') and float('3') give you 3.0, but int('3.0') gives you the error.
It might be better to validate a right when it is input.
try:
a = int(input("Enter 'a' "))
except ValueError:
print('PLease input a valid integer')
This either casts a to an int so you can be assured that it is an integer for all later uses or it handles the exception and alerts the user
int() casting can't handle string numbers that have decimal points
- example --> int('13.5') will give you error , but int('13') will convert the
string to integer
Why : This considered as explicit casting required by the user as it prevents you from losing information like 0.5 if you read dataset and don't know it's had floating-point numbers
Work Around >
int(Float("13.5"))
A real-world example I faced: where I wanted the numbers as int while int(I["mpg"]) directly didn't work so I used float() then int()
sum([int(float(i["mpg"])) for i in file])//len(file)
I have a train dataset which has 43 attributes. Each of the attributes have some tuple values as objects (as in strings with certain characters).
Now, I'm trying to scale the values using a scaler, but it gives the following error:
could not convert string to float: '?'
Now, I don't know how to convert objects to int or float in a single command and converting it for each of the 43 attributes one by one is a bit tedious.
So I want to know how to do it for the complete dataset with a single command.
I use the convert function which tries to parse the string as a float.
If it cannot, it tries to parse it as a int, and if it still cannot, assigns the value 0 (you can change the default value is the string is not a int or a float to something else)
l = []
def convert(str):
x = 0
try:
x = int(str)
except:
try:
x = float(str)
except:
pass
l.append(x)
for i in ['1','2','3','?','4.5']:
convert(i)
print(l)
#[1, 2, 3, 0, 4.5]
I am new to coding and is trying to solve this python question
Question:
Write a program that calculates and prints the value according to the given formula:
Q = Square root of [(2 * C * D)/H]
Following are the fixed values of C and H:
C is 50. H is 30.
D is the variable whose values should be input to your program in a comma-separated sequence.
Example
Let us assume the following comma separated input sequence is given to the program:
100,150,180
The output of the program should be:
18,22,24
Hints:
If the output received is in decimal form, it should be rounded off to its nearest value (for example, if the output received is 26.0, it should be printed as 26)
In case of input data being supplied to the question, it should be assumed to be a console input.
This is the solution given. I have not seen 'x for x in input()'expression, may I know what does this expression do ?
import math
c=50
h=30
value = []
items=[x for x in input().split(',')]
for d in items:
value.append(str(int(round(math.sqrt(2*c*float(d)/h)))))
print (','.join(value))
This is my own solution but somehow I got a syntax error.
def sr(D):
For item in D:
return ((2*50*D)/30)**0.5
try:
a=int(input())
j=a.split(",")
print(sr(j))
except:
print('Please enter an integers or intergers seperated by comma')
The x is just a variable that gets assigned to the input that comes in via the input() function.
If you're aware of C style language (or Java), it's similar to
for(int i=0;<some_condition>;<some_operation>){}
This is just a condensed, pythonic and easy to read way to do this.
You can read more Python loops here
https://wiki.python.org/moin/ForLoop
I'm a beginner at programming and what I want is to place a condition in which I write a real number and want the program to tell me whether it's a fractional or an integer.
I'm starting with:
x = float(input("Writte a real number: "))
and then I thought of using a double condition in which I would do something like:
if type(x)==int:
print("integer number")
and another one with float instead of int (or use an else, since I say before to write a real number). But I guess this isn't right since I predefine x as a float. Another problem would be the numbers like 2.0 or 3.0 since they are integer but I would get them as fractionals.
You can achieve this by using an important property of integers: the floor and ceiling value of an integer would be the same; whereas, for a floating-point number, these values would differ by 1.
So, you could do something like:
import math
x = float(input("Writte a real number: "))
if math.ceil(x) == math.floor(x):
print("integer number")
The floor of a number x is the largest integer less than or equal to x.
The ceiling of a number x is the smallest integer greater than or equal to x.
You can see some examples of floor and ceiling here.
Inspired by #Carcigeniacte's comment. You can leave it as a string initially, check the conversions against each other; then if they are the same, it's an int, otherwise it's a float. After that, convert it to whichever numerical type is appropriate for the calculations later. Just don't forget to check for a bad input:
while True:
x = input('write a real number: ')
try:
float(x) # Checking the input can be converted to a number
break
except ValueError:
print('\nPlease input a number') # runs if it can't be converted
continue
if float(x) == int(x): # looking for integers
print('\nInteger Number')
x = int(x)
else:
print('\nFractional Number')
x = float(x)
For educational purposes, I am trying to build an efficient algorithm to find the Least Common Multiple. I already have a quadratic and slow implementation for that. I am trying to build a new one. My new implementation uses a math property involving the Greatest Common Divisor (GCD) and the Least Common Multiple (LCM).
Basically: For any two positive integers a and b,
LCM(a, b) * GCD(a, b) = a * b
I am using Python 3 for that.
I have a very efficient implementation for GCD (it uses another math property, but it is pointless to talk about that):
def euclidean_gcd(a,b):
if b == 0:
return a
else:
a_prime = a%b
return euclidean_gcd(b,a_prime)
My implementation for LCM is:
def lcm_fast(a,b):
return (int((a*b)/(euclidean_gcd(a,b))))
However, when I call:
lcm_fast(1023473145,226553150)
I get as an output:
46374212988031352
The correct answer would be a close number:
46374212988031350
I am a beginner (second year on the Applied Math major), why is this happening?
I am not sure if I could grasp the concept of integer overflow, but, according to my understanding above a little research I did, there is no integer overflow in Python.
I did stress testing and tried to find this mistake in a easier to understand case. However, the problem seems to happen only with really big numbers. Bellow you can check my stress testing for that:
import random
#defina a fronteira máxima dos testes randômicos
print ("insira um número para ser o final do intervalo de testes aleatórios")
bound_right = int(input())
#versão lenta, ou naive
def check_elem_in_list(list_1,list_2):
for element in list_1:
if element in list_2:
return element
else:
return False
#nested loops, vai ter comportamento quadrático
def lcm_slow(num_1,num_2):
list_of_num_1_prod = []
list_of_num_2_prod = []
max_nums = max(num_1,num_2)
end_range = max_nums +1
for i in range(1, end_range):
list_of_num_1_prod.append(i*num_1)
list_of_num_2_prod.append(i*num_2)
if check_elem_in_list(list_of_num_1_prod,list_of_num_2_prod) != False:
return (check_elem_in_list(list_of_num_1_prod,list_of_num_2_prod))
def euclidean_gcd(a,b):
if b == 0:
return a
else:
a_prime = a%b
return euclidean_gcd(b,a_prime)
def lcm_fast(a,b):
return (int((a*b)/(euclidean_gcd(a,b))))
# está dando pau com os inputs 1023473145, 226553150
# vou fazer stress testing
#primeiro, fazer função para gerar testes
a_in = random.randint(1,bound_right)
b_in = random.randint(1,bound_right)
while (lcm_slow(a_in,b_in)==lcm_fast(a_in,b_in)):
a_in = random.randint(1,bound_right)
b_in = random.randint(1,bound_right)
print (a_in,b_in,"OK",lcm_fast(a_in,b_in),lcm_slow(a_in,b_in))
if (lcm_slow(a_in,b_in)!=lcm_fast(a_in,b_in)):
print (a_in, b_in,"OPS",lcm_fast(a_in,b_in),lcm_slow(a_in,b_in))
break
#
EDITED AFTER SOME COMMENTS/ANSWERS TO THE ORIGINAL PROBLEM
Inside this problem, a new problem arrives.
I am building this for a platform. My solution is right. After the comment from Blender. I did that (which was my original solution):
def lcm_fast(a,b):
a = ((a*b)/(euclidean_gcd(a,b)))
return a
The problem is that I receive this message failing on the platform's test cases:
Failed case #1/42: Cannot check answer. Perhaps output format is wrong.
Input: 18 35 Your output: 630.0 Correct output: 630 (Time used: 0.01/5.00, memory used: 9613312/536870912.)
That's funny. If I avoid the approximation with int(), the code is right for big numbers. However, without the conversion from float to int, I am unable to provide the answer on the desired format.
You're converting the result of your division back into an integer with int() because "regular" integer division results in a float. CPython's floats have a fixed precision, so your conversion back and forth will result in lost information for sufficiently large numbers.
Avoid losing precision and perform floor division with //, which returns an integer:
def lcm_fast(a,b):
return (a * b) // euclidean_gcd(a,b)
In python 3, standard division (/) operations will automatically promote to float, while integer division (//) will always return an int.
Thus, python can handle arbitrarily large ints, at some point your data is being treated as a float rather than an int, subjecting it to floating point precision error.
(I see someone else also typed up a similar answer while I was writing this up and feel obligated to make note of this before being bashed to death for copying someone else's answer.)