Convert value in a Python dictionary to an int [duplicate] - python

I have an issue that really drives me mad. Normally doing int(20.0) would result in 20. So far so good. But:
levels = [int(gex_dict[i]) for i in sorted(gex_dict.keys())]
while gex_dict[i] returns a float, e.g. 20.0, results in:
"invalid literal for int() with base 10: '20.0'"
I am just one step away from munching the last piece of my keyboard.

'20.0' is a string, not a float; you can tell by the single-quotes in the error message. You can get an int out of it by first parsing it with float, then truncating it with int:
>>> int(float('20.0'))
20
(Though maybe you'd want to store floats instead of strings in your dictionary, since that is what you seem to be expecting.)

It looks like the value is a string, not a float. So you need int(float(gex_dict[i]))

It looks like the problem is that gex_dict[i] actually returns a string representation of a float '20.0'. Although int() has the capability to cast from a float to an int, and a string representation of an integer to an int. It does not have the capability to cast from a string representation of a float to an int.
The documentation for int can be found here:
http://docs.python.org/library/functions.html#int

The problem is that you have a string and not a float, see this as comparison:
>>> int(20.0)
20
>>> int('20.0')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '20.0'
You can workaround this problem by first converting to float and then to int:
>>> int(float('20.0'))
20
So it would be in your case:
levels = [int(float(gex_dict[i])) for i in sorted(gex_dict.keys())]

Related

Cannot convert input as fraction string to float

Here is my program :
r = float(input())
for i in range (1,6):
L = r-i
k = L//2
if isinstance(k, int):
print(L, r-L)
else :
print("IDK !")
When i plug in 17/6 this is the error that i get:
Traceback (most recent call last):
File "python", line 1, in <module>
ValueError: could not convert string to float: '17/6'
Thanks for helping me !
First off, you need to reformat your code so that it's readable for other people. But to answer your question, it's because "17/6" comes in as a string value. Converting a string to a float will convert actual numbers into a float. Numbers in Python are represented as decimals, not fractions, so 17/6 is "17 divided by 6" and not "17 over six". You would need to find a way to parse that as an operation to produce a float instead of trying to convert it directly to a float.
EDIT: To clarify, I understand that the fraction 17/6 and the results of dividing 17/6 are mathematically equivalent. That does not mean that python treats them as equivalen representation because fractions are not a native data type. If you print 17/6, it's not showing you a representation of 17/6. It's printing the result of 17.truediv(6).
I don't quite understand what your trying to do but if you want Python to evaluate your input say 17/6 as if you where to have input the result of 17/6 as a float (2.833333333333333) replace
r = float(input())
with
r = float(eval(input()))
eval will evaluate the input string ("17/6") as 17.truediv(6) which is a float and then save that to r
also in my tests the line
if isinstance(k, int):
always evaluates to false as // doesn't change type to int and even if id did it would do so consistently

Why does the following evaluate to a ValueError in python?

We were coding something awhile ago and we came across a small problem. We wanted to try to convert float numbers to integers
Here is the code:
x = int(input(())
print x
We tried the code and put 5.5. It evaluated to a ValueError. Logically, it is sound in logic. But if we try the following code:
x = int(float(input(())) OR x = int(5.5), it evaluates to a value of 5.
Why does this happen?
In the first case, you are calling int("5.5"), because input() returns a string. that's a ValueError because 5.5 is not an int, and the designers of python decided not to do any implicit casting.
In the second case, you care calling float("5.5"), which is 5.5 because "5.5" can be converted to a float as you asked, and then int(5.5), which is the result of converting a float to an int (python uses truncation for this; you can call round() instead if that's not what you want).
The third case is just the same as the second step of the second case.
Its because of input() takes the value as a string data type. When you are taking "5" then converting into int() works but converting string input "5.5" to int() will give error as this is not supported by python. In such a case, you have to first convert it to float() and then int() to get an integer value.
I think x = int(5.5) didn't lead to any value error. First problem is, yeah, you cannot directly compare it an input result with int or float. To make sure it let's do this little experiment:
>>> x = input()
>>? 20
>>> print(type(x))
>>> <class 'str'>
From this experiment, you see that even you enter "any numerical" to input, it will return your input as string. And let's check what's going on with int(input()) operation:
x = int(input())
5.5
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '5.5'
This problem happen when you try to 'directly' convert a float to integer. Python cannot convert literally float to int directly. There's another trick to help this, by assign float as the number original datatype. This is happen when and let's see if we add float as another parser :
x = int(float(input()))
5.5
print(type(x))
<class 'int'>
The solution is simple, just directly parse your input as int, then compare it:
x = int(float(input()))
if x == 5 or x == int(5.5):
#do something
Hope it will help you. Good Luck!

why I get error when using int() function to convert float to integer?

Why do I get an error When I tried to use int() function to convert a float to integer?
>>> int('99.99')
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
int('99.99')
ValueError: invalid literal for int() with base 10: '99.99'
I expected the result to be 99
Your argument isn't a float, it's a string containing the representation of a float. You have to convert it to a float first, then you can convert that to an int.
int(float('99.99'))
Per the docs
Return an integer object constructed from a number or string x, or
return 0 if no arguments are given. If x is a number, return
x.int(). For floating point numbers, this truncates towards zero.
If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in radix
base.
Pay particular attention to "representing an integer literal". So your str that you are attempting to convert cannot be a float, because that's a float literal, not an int literal.
So, as others have noted, you cannot go directly from a float literal to an int, you need to convert the float first:
x = '123.45'
int(float(x))
You are getting a ValueError because you are overloading int() with an argument that is not consistent with the Python docs.
According to the doc:
"If x is not a number or if base is given, then x must be a string or
Unicode object representing an integer literal "
Basically, x (in your case '99.99') is the string 99.99 which does not satisfy the requirements of being an integer literal. You provided a floating literal.
TL;DR
int(float('99.99'))

Why do conversions of different number formats not work as expected in Python?

This works:
[IN] int(str(8))
[OUT] 8
This does not work:
[IN] int(bin(8))
[OUT] ValueError: invalid literal for int() with base 10: '0b1000'
[IN] int(hex(8))
[OUT] ValueError: invalid literal for int() with base 10: '0x8'
This is also weird:
[IN] bin(str(8))
[OUT] TypeError: 'str' object cannot be interpreted as an integer
# What are you telling me, Python?! You just did it with int()!
But:
[IN] float(str(8))
[OUT] 8.0
Even worse:
[IN] int(8.5)
[OUT] 8
[IN] int(str(8.5))
[OUT] ValueError: invalid literal for int() with base 10: '8.5'
[IN] float(str(8.5))
[OUT] 8.5 # IT WORKS??!
This makes int(some_string) a bad choice and instead int(float(some_string)) should be preferred!
Or:
[IN] hex(hex(8))
[OUT] TypeError: 'str' object cannot be interpreted as an integer
Bad design: A method that converts an object to the type it belongs to should always accept its own type as a valid input. (I know the type is str, but anyway).
[IN] complex(str(complex(8)))
[OUT] (8+0j)
# What are the rules again?
[IN] int(abs(complex(str(8.5))))
[OUT] 8
# OK... I guess?
This seems very anti-Pythonic to me. Is there a design reason why these very intuitive conversions don't work, or is it simply something that noone thought about and that needs to be improved? Or maybe I'm doing it the wrong way?
The only solution I found is
[IN] eval(hex(8))
[OUT] 8
[IN] eval(bin(8))
[OUT] 8
The int constructor accepts a second argument to specify the base that a first string argument should be interpreted in. So your examples with bin and hex would work if you specified base 2 and 16 respectively. Python won't use the prefix on the number to guess the base for you unless you specify the "special" base 0, which tells it to use the prefix to determine the base (otherwise appropriate prefixes are ignored and invalid ones cause exceptions). You can see that your issue is base related in the exception message, which specifically say the input values are not valid "for int() with base 10".
Similarly, Python won't implicitly truncate the fractional part of the string representation of a decimal value when creating an int. If you want to convert the string "8.5" to the integer 8, you need to first parse the string to a float (with e.g. val = float("8.5")), then convert the value to an integer, discarding the fractional part (e.g. int_val = int(val)). You can of course chain them together (int(float("8.5"))), but Python won't ever do the combined operation automatically for you.
I think you have a few fundamental misunderstandings here. Lets go through a couple of the various functions you called out. To start, lets look at int, and just try running help:
>>> help(int)
class int(object)
| int(x=0) -> int or long
| int(x, base=10) -> int or long
|
| Convert a number or string to an integer, or return 0 if no arguments
| are given. If x is floating point, the conversion truncates towards zero.
| If x is outside the integer range, the function returns a long instead.
|
| If x is not a number or if base is given, then x must be a string or
| Unicode object representing an integer literal in the given base. The
| literal can be preceded by '+' or '-' and be surrounded by whitespace.
| The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to
| interpret the base from the string as an integer literal.
| >>> int('0b100', base=0)
| 4
So int(foo) converts a string or number-type to an integer. Seems reasonable.
>>> help(bin)
bin(...)
bin(number) -> string
Return the binary representation of an integer or long integer.
And here bin(foo) converts an integer to a string (e.g.: "0b1010111")
Note that numbers in python are not bin or hex - those are bases. They are numbers, and can be stored as an int, float, long, etc. As a convenience to you the interpreter is happy to convert things like 1e6, 21.4, 0x12, 0777 into their respective number equivalent, but that doesn't mean that the numbers have "string" as a native format, or the base of the number that the representation was given is stored along with the value.
The root of your confusion seems to be that you are taking str as a first class object - perhaps because that is what is used to type code? The sentence (emphasis mine):
Bad design: A method that converts an object to the type it belongs to should always accept its own type as a valid input. (I know the type is str, but anyway).
Highlights this root.
To assume that bin would work for a string as well as an integer in python is somewhat silly, in the same way the expecting int("the smallest prime larger than the population of florida") is a bit silly. They do what they are documented to do.
A loose language such as Wolfram Alpha might take these in stride, while a strict language like Haskell might laugh at the concept of even allowing multiple types and argument counts for the same function.
For completeness:
bin('8'), hex('0x8') # Correctly rejects a non-integer
int('0b1000'), int('0x8'), int('8.5') # Correctly rejects non-integer string
int('0b1000', base=0), int('0x8', base=0) # Correctly performs slower interpretation depending on the string base
int('8.5', base=0) # Still correctly rejects non-integer string
int(8.5) # Correctly 'truncates a floating point towards 0'
eval(foo) # Please avoid use of eval, there are no common correct applications of this function
Highlighting this comment from Alan Leuthard:
There are two different int() functions. One accepts a single input
and is extremely fast. The other is slower and allows casting to
different bases. Efficiency of an often used built-in function is the
reason for the lack of features you want.
Let's see here:
This works:
[IN] int(str(8))
[OUT] 8 This does not work:
[IN] int(bin(8))
[OUT] ValueError: invalid literal for int() with base 10: '0b1000'
[IN] int(hex(8))
[OUT] ValueError: invalid literal for int() with base 10: '0x8'
There are no built-in hexadeximal or binary objects, only the string representations created by the built-in functions. You can always create them, if you'd like. So you're not casting from an int to a bin to an int, you're casting from a str to an int. Expecting the built-in int() function to recognize every string representation of a number is a bit much.
EDIT: I stand corrected, there's a second input to put a base. So int(hex(8), 16) would give you 8 and int(bin(8), 2) would also give you 8. Fancy that! Those Pythonistas think of everything...and now I learn a bit too!
This is also weird:
[IN] bin(str(8))
[OUT] TypeError: 'str' object cannot be interpreted as an integer
# What are you telling me, Python?! You just did it with int()!
bin() doesn't accept strings. Only integers. Write your own if you need it. It also only outputs a formatted string.
But:
[IN] float(str(8))
[OUT] 8.0
Yeah. Float accepts string representations of integers. bin() isn't as useful or as ubiquitous as float()
Even worse:
[IN] int(8.5)
[OUT] 8
[IN] int(str(8.5))
[OUT] ValueError: invalid literal for int() with base 10: '8.5'
[IN] float(str(8.5))
[OUT] 8.5 # IT WORKS??!
This makes int(some_string) a bad choice and instead int(float(some_string)) should be preferred!
Double casting (from a string to a float) in a single function is a bit much to ask. It requires int() to accept way too many inputs for a built-in function. The string has to be a representation of an int already. Simple and clear. And yes, if your string might be a float, cast it to a float first, then into an int. Not really much more work. You could always catch the exception, too!
Or:
[IN] hex(hex(8))
[OUT] TypeError: 'str' object cannot be interpreted as an integer Bad design: A method that converts an object to the type it belongs to
should always accept its own type as a valid input. (I know the type
is str, but anyway).
hex() creates a string. You answered your own question. If you want a Hex object, I believe there are several packages that implement them.
[IN] complex(str(complex(8)))
[OUT] (8+0j)
# What are the rules again?
[IN] int(abs(complex(str(8.5))))
[OUT] 8
# OK... I guess?
complex() takes a string representation of a complex as a valid input. That doesn't seem strange at all. Nor is it strange that int takes the absolute value of a complex (since all it has to do is ignore the imaginary part). Here, we see the effect of having an actual object implemented. Complex numbers are fully implemented in the built-in environment. Hex and Bin are not.
This seems very anti-Pythonic to me. Is there a design reason why
these very intuitive conversions don't work, or is it simply
something that noone thought about and that needs to be improved? Or
maybe I'm doing it the wrong way?
The only solution I found is
[IN] eval(hex(8))
[OUT] 8
[IN] eval(bin(8))
[OUT] 8
You can argue that Hex and Bin should be fully implemented objects in the built-in environment. But, currently, they aren't. Find a package that does it, or write your own objects.

python float to in int conversion

I have an issue that really drives me mad. Normally doing int(20.0) would result in 20. So far so good. But:
levels = [int(gex_dict[i]) for i in sorted(gex_dict.keys())]
while gex_dict[i] returns a float, e.g. 20.0, results in:
"invalid literal for int() with base 10: '20.0'"
I am just one step away from munching the last piece of my keyboard.
'20.0' is a string, not a float; you can tell by the single-quotes in the error message. You can get an int out of it by first parsing it with float, then truncating it with int:
>>> int(float('20.0'))
20
(Though maybe you'd want to store floats instead of strings in your dictionary, since that is what you seem to be expecting.)
It looks like the value is a string, not a float. So you need int(float(gex_dict[i]))
It looks like the problem is that gex_dict[i] actually returns a string representation of a float '20.0'. Although int() has the capability to cast from a float to an int, and a string representation of an integer to an int. It does not have the capability to cast from a string representation of a float to an int.
The documentation for int can be found here:
http://docs.python.org/library/functions.html#int
The problem is that you have a string and not a float, see this as comparison:
>>> int(20.0)
20
>>> int('20.0')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '20.0'
You can workaround this problem by first converting to float and then to int:
>>> int(float('20.0'))
20
So it would be in your case:
levels = [int(float(gex_dict[i])) for i in sorted(gex_dict.keys())]

Categories

Resources