Numbers passed as command line arguments in python not interpreted as integers - python

I am familiar with C, and have started experimenting in python. My question is regarding the sys.argv command. I've read it is used for a command line interpreter, but when trying to execute a simple program I don't get the results I expect.
Code:
import sys
a = sys.argv[1]
b = sys.argv[2]
print a, b
print a+b
Input:
python mySum.py 100 200
Output:
100 200
100200
When I add the two arguments they are concatenated instead of the two values being added together. It seems that the values are being taken as strings.
How can I interpret them as numerics?

You can convert the arguments to integers using int()
import sys
a = int(sys.argv[1]) b = int(sys.argv[2])
print a, b
print a+b
input: python mySum.py 100 200
output:
100 200
300

You also should validate the user input:
import sys
def is_intstring(s):
try:
int(s)
return True
except ValueError:
return False
for arg in sys.argv[1:]:
if not is_intstring(arg):
sys.exit("All arguments must be integers. Exit.")
numbers = [int(arg) for arg in sys.argv[1:]]
sum = sum(numbers)
print "The sum of arguments is %s" % sum

Indeed, you have found the problem yourself, sys.argv is an array of strings.
You can transform a string to an integer with int(). In this case for example: a = int(sys.argv[1])

sys.argv items are always strings. you should cast them to int with int(a).
You can also use third party libraries for handling CLI arguments such as OptParse.

In Python, strings are not implicitly converted to integers.
Try
num1 = int(sys.argv[1])
This would represent the numerical value of the number, not its string representation.

Beware of performing comparisons involving command-line arguments, which can lead to really unexpected behavior owing to Python 2's policy for comparing objects of different types ('int' < 'list' < 'string' < 'tuple') as noted here. In Python 3, comparing objects of different types will lead to a TypeError.
For an example of object comparison mayhem, try removing the int() call in section 6.1.1. of the Python tutorial Fibonacci code and you'll get an infinite loop, since the while loop condition becomes: 'int' < 'string'. (This would not happen in Perl, btw).
Great advice from #Jan-Philip above to validate command-line arguments, even for Python 3.

Related

How does the random.seed function in python work for words? What number is it converted to?

I realized that if I choose
random.seed("hello world!")
it actually works, i.e. it does not give me any error and it works like a normal seed; So for example choosing
random.seed("hello world!")
random.choices([1,2,3,4,5,6,7], k = 10)
keeps giving me the same output; But it would be actually interesting, to what number a string is converted to??
The code in random.py looks like this:
# more code here
# Note there is a entirely different algorithm for "version 1"
elif version == 2 and isinstance(a, (str, bytes, bytearray)):
if isinstance(a, str):
a = a.encode()
seed = int.from_bytes(a + _sha512(a).digest())
# some more irrelevant conditions
super().seed(seed)
So basically the number will be the "input string + sha512 of the input string" interpreted as one very big integer. Python integers have no max value so this always works.

Using input() as parameter for range() in Python

How does input() work as a parameter to range() in Python?
For example:
Say the user inputs multiple numbers 10 and 2 or more literally type "10 2"
for i in range(int(input())):
try:
a,b=map(int,input().split())
print(a//b)
except Exception as e:
print("Error Code:",e)
What range does the for loop use then? Is it (0,10), (0,2) or something else? Or, said differently, which number does the range use for the upper limit if the user inputs multiple numbers? More generally, I am trying to understand the purpose of the for loop here and why the code can't just be:
try:
a,b=map(int,input().split())
print(a//b)
except Exception as e:
print("Error Code:",e)
input() values will be stored as str.
It all comes down to what the user inputs. The piece of code you provided is very bad, because the user has to guess what to input and when. But the logic works as follows:
If you type in a single value, then int(input()) will convert that value to integer. For example, if you input 2, then input() will hold the string "2" and int("2") will yield integer 2.
If you have multiple values, then you cannot convert to int right away, because what the hell does int("2 10") mean? That is why you have to use .split(), to separate these multiple values in many singular values. For example, if you run x = input() and type in 2 10, then x will hold the string "2 10". Now, "2 10".split() yields the list of strings ["2", "10"].
The piece of code map(int,input().split()) comes in to convert this list of strings to a list of integers. It maps each value to a new value using the function int to transform it.
Now that this is established, it becomes easier to understand how this works in a for loop using range.
The range type, as per docs, may have one parameter stop or three arguments (start, stop [, step]) in its constructor. These arguments are all integers.
Thus, the values from input() have to fit this structure. If you type in 2 10 in input, and try to do range("2 10"), you'll receive an error. Because you are passing one argument of type str. That is why you have to convert to integer first. But you cannot convert "2 10" to integer right away, as we just discussed. That is why you have to split first, and then convert each value to int, and just then pass these as arguments to range().
So, to summarize, given x = input() and you type in 2 10, here is what does not work:
>>> int(x)
>>> range(x)
what does work:
>>> a,b=map(int,input().split())
>>> range(a, b)
The first input() will determine the stop condition of the for loop
Which means the first input() determines the number of time your for loop will be executed
Other input() will assign the values to a and b as string
The above is equivalent to:
stop = input()
stop = int(stop)
for i in range(stop):
try:
a,b=map(int,input().split())
print(a//b)
except Exception as e:
print("Error Code:",e)
But if the first input() is given as "10 10" then the code will throw you an error something like the string can not be converted to int
The a,b=map(int,input().split()) means you are expecting an input of two numbers separated by spaces and these inputs will be given exactly stop number of times
This pattern is used when you want to read n lines from the input, for example the input is:
3
1 2
3 4
5 6
The first input will determine how many times the for loop needs to be run to read all the lines.
For a single line of input like "10 2" you don't need to use a loop.

multiple inputs using int instead of eval

Small question: Why doesn't this piece of code work when I use int but does when I use eval?
int can only take one input? Is there a way to make it take multiple inputs as concise as using eval? Int is a stronger condition so that's why I am curious about how it would work.
a,b,c = int(input("enter numbers: "))
print(no_teen_sum(a,b,c))
This gives ValueError: invalid literal for int() with base 10, but the following code does work.
a,b,c = eval(input("enter numbers: "))
print(no_teen_sum(a,b,c))
int takes one input and possibly a base:
>>> int('46',7) # 46 is 34 in base 7
34
But you can use int along with map:
>>> map(int,['1','2','3'])
[1, 2, 3]
Use list comprehension:
def main():
numbers = input("enter numbers: ").split()
print(no_teen_sum(*[int(n) for n in numbers)])
main()
Python is trying to parse the whole string as one integer rather than three.
What you could do is:
a, b, c = map(int, input("enter numbers: ").split())
This way you are splitting the list into three strings, and then converting (mapping) each string to an int.
int can only take one input?
Yes, and that is technically true for eval, too. It's just that eval might return something other than an int. In your case, I'm assuming you enter something like 1, 2, 3 on the input prompt. eval simply parses that as a tuple, which it returns, and unpacks into your three variables.
You can, however, easily achieve something similar to what you want using list comprehension:
a, b, c = [int(x.strip()) for x in input("Enter numbers: ").split(",")]
This has the added benefit that you don't risk having some completely unexpected type returned from eval.
One caveat with using eval that should perhaps be worth noting is that it accepts any valid Python syntax and executes the parsed result, which may include arbitrary function calls, including code to erase your hard drive. Not much of a problem when you're just writing a program for yourself to use, but just so that you know.

How to make random numbers with variables in python?

I encountered a problem while programming in Python, and here's a bite of my program:
import random
p = raw_input('Percent Probability Program\nWhat percent?\n ')
r1 = random.randint(p, 100)
It gave me an error that the first value in the random command wasn't an integer. Please help!
Python 2
raw_input returns a str object, which is basically a string - no math operations can be performed on strings, and it's not the correct type for randint.
You can either convert your input to int using int(raw_input()) or just use the method input(), which returns an evaluated value (in your case, it should return an int)
Python 3
In python 3, the input function returns an str object, so converting it to int will be int(input())

Concatenate string and int in Python 3 .4 [duplicate]

This question already has an answer here:
How can I concatenate str and int objects?
(1 answer)
Closed 1 year ago.
I'm new to Python, so I've been running through my own set of exercises to simply start memorizing basic functions and syntax.
I'm using the PyCharm IDE and Python 3.4. I've run into an issue when running through some basic string and integer concatenation exercises. Each instance below is throwing an unsupported operand type. There are several threads on Stack Overflow that clearly states proper concatenation syntax, but the above error message continues to plague me.
print ("Type string: ") + str(123)
print ("Concatenate strings and ints "), 10
In Python 3+, print is a function, so it must be called with its arguments between parentheses. So looking at your example:
print ("Type string: ") + str(123)
It's actually the same as:
var = print("Type string: ")
var + str(123)
Since print returns nothing (in Python, this means None), this is the equivalent of:
None + str(123)
which evidently will give an error.
That being said about what you tried to do, what you want do to is very easy: pass the print function what you mean to print, which can be done in various ways:
print ("Type string: " + str(123))
# Using format method to generate a string with the desired contents
print ("Type string: {}".format(123))
# Using Python3's implicit concatenation of its arguments, does not work the same in Python2:
print ("Type string:", str(123)) # Notice this will insert a space between the parameters
Note that print is a function in Python 3. In Python 2, your first line would concatenate "Type string: " and "123" and then print them. In Python 3, you are calling the print function with one argument, which returns None, and then add "123" to it. That doesn't make any sense.
The second line doesn't generate an error in Python 2 or 3 (I've tested it with 2.7.7 and 3.2.3). In Python 2, you get
Concatenate strings and ints 10
while in Python 3, your script should only print
Concatenate strings and ints
This is because again, print is a function, and therefore you call it with the argument "Concatenate strings and ints". The , 10 makes your line a tuple of the return value of print, which is None, and 10. Since you don't use that tuple for anything, there is no visible effect.
Try format():
print("Type string: {}".format(123))
print("Concatenate strings and ints {}".format(10))
There is nothing wrong with this:
print ("Type string: ") + str(123)
print is just a function like anything else. And you're calling that function with one argument, "Type string: ", and then trying to add the result (which will be None) to the string '123'. That isn't going to work. If you wanted to add the two strings together, you have to put them into the same expression, inside the parentheses:
print("Type string: " + str(123))
Similarly:
print ("Concatenate strings and ints "), 10
This calls print with one argument, and then makes a tuple of the None returned by print and the number 10. If you want to pass 10 to the print call, it has to go inside the parentheses:
print("Concatenate strings and ints ", 10)
As gitaarik's answer points out, using str.format is more flexible, and avoids the possibility of problems like this. It also gives you code that works exactly the same way in both Python 2.6-2.7 and Python 3.x, which is pretty nice even if you aren't trying to write dual-platform/single-codebase code, because it'll be understandable even to people who only know one or the other.
I think this is a pretty cool way to concatenate a string and an int in Python:
print (f"Type string: {123}")
print (f"Concatenate strings and ints {10}")
You can do it like this:
c = 'Emerson'
d = 32
print("My name is %s and I am %d years old." %(c,d))
Result:
My name is Emerson and I am 32 years old.

Categories

Resources