Strange python syntax, or in print statement - python

I can't find anything about this, so I'm forced to ask here. I'm sure it's an easy question for anybody who knows python well.
python 2:
print raw_input() == 0 or hash(tuple(map(int, raw_input().split(' '))))
python 3:
print(input()==0 or hash(tuple(map(int,input().strip().split()))))
I am trying to understand why an 'or' is in a print statement.
The code in question has a boolean operator inside a print statement, comparing a boolean and an int. This is what I need explained to me. It is obviously specific to python. What would the code print in the case that input()==0 returns true? How can we compare a boolean and a hash, and again, what are we doing making boolean comparisons inside a print statement?

In Python, comparisons with or or and make use of two features:
Truthy and falsey values, and
Short-circuiting.
So, when you have something like this:
print(input()==0 or hash(tuple(map(int,input().strip().split()))))
It'll follow the order of operations, checking whether input() returns a 0. Since it's that or the next term, if it's true then the next term has no impact on the result and won't be evaluated. If that happens, it'll print True, since that's what's returned by input()==0.
If that's false, it'll evaluate the next part, getting input, mapping it as an integer, turning it into a tuple, and hashing it. It'll then return that hash whether or not it's a truthy value (a number other than 0, a sequence or set with contents, etc.).

Python will first evaluate whether or not input()==0 is True. If it is, then Python will print it and ignore the rest of the line. If the input is not equal to 0 and this evaluates as False, then it will be ignored and the rest of the line will be printed regardless of how it evaluates. So even if the rest of the line would evaluate as False, Python will print its result.
A clearer example would be setting the name of something based on user input and requiring a default value.
name = raw_input("What is your name?")
print ("So your name is...")
print (name or "John Smith")
name will be evaluated as True or False. Since an empty string will be considered False, if the user enters nothing then instead Python will print the default name after the or operator.

I am guessing that your code is Python3, since otherwise it is unlikely that the result of input() would have a strip method.
Here is a long form of the code, with explanations.
# Read a line of input. Returns a string.
a = input()
# Compare to integer 0, always False.
# Effectively, this ignores the first line of input.
b = a == 0
# Separate function to represent lazy evaluation.
def y():
# Get a second line of input, as a string.
c = input()
# Strip leading and trailing whitespace, still a string.
# This line is useless since split() with no argument does this.
d = c.strip()
# Split the line by any runs of whitespace. Returns a list of strings.
e = d.split()
# For each string in the list, convert it to an integer in base 10.
# Return an iterator (not list) of ints.
# Most people would write (int(s) for x in e) for a generator
# comprehension, or [int(s) for x in e] for a list comprehension.
m = map(int, e)
# Consume the iterator into a tuple of ints.
# Note that it can't be a list, because lists aren't hashable.
t = tuple(m)
# Hash the tuple, returning a single int.
return hash(t)
# If b is truthy, set x to it. Otherwise, evaluate y() and set x to that.
# Unlike many languages, the arguments to or are *not* coerced to bool.
# Since b is False, y() will be evaluated.
x = b or y()
# Print the result of y().
# i.e. the hash of the tuple of ints on the second line.
# This is essentially a meaningless number.
print(x)

Related

Palindrome Coding issue

Writing a program:
Input string from the user
print out whether this string is a palindrome or not
Also, I found a few other codes online but want to work with this code only.m Please let me know the error
i = str(input())
for item in i:
print(item)
if int(i[item]) == int(i[-item]):
print('yes')
else:
print('no')
Use a String slice (The i[::-1] will reverse the string):
i = input()
if i == i[::-1]:
print("Yes")
else:
print("No")
This will take the input from the user and compare it against the same input in reverse.
try this:
word="TOT"
i=word[::-1]
if i==word:
print("palandrom")
Although for item in i: loops through every character in the string, there are several problems with your code line if int(i[item]) == int(i[-item]):. First of all, item is going to be a character from your string. So if the user types "hello", then i[item] first looks for i['h']. Since 'h' is a character and not a number, this makes Python think that i is a dictionary and not a string, and thus tells Python to look for a dictionary named i and return the value where the key is h. That won't work since i is your original string, not a dictionary.
It looks like what you meant to do here is compare i[0] (the first character in the string) to i[-1] (the last character in the string), then i[1] to i[-2], and so on. But even you if looped through the position numbers, i[-item] doesn't mathematically give you what you want.
Yet another issue here is that you're checking each character one at a time and returning "yes" or "no". What you ultimately want though is to output one simple answer: whether your string is a palindrome or not.
Also, there's no need to put str() around input(), since input returns a string anyway, even if the user enters only numerals. By the way, even though you're using i as your string variable, the usual convention in programming is to use i to denote some sort of integer, such as one you're iterating through in a for loop. But that's OK for now.
As some of the other answers have shown, i[::-1] is a quick way to return the reverse of a string itself. So if you're OK with seeing the output return True if the string is a palindrome and False if it isn't, then here's an extremely simple way to do it:
i = input()
print(i == i[::-1])
If the string i is identical to itself reversed, then i == i[::-1] returns True. If not, it returns False. The print statement then prints whichever the answer is.
However, if you really do want to do it the long way, testing character by character in a loop, then here's one way to do it. You could make a function that takes in a string and does the work:
def is_palindrome(mystring):
# The "//2" here divides by 2 and ignores the remainder. So if
# there are an even number of letters, we'll test each pair. If
# It's an odd number, then we don't care about the middle character
# anyway. Compare [0] to [-1], then [1] to [-2], [2] to [-3], and so on.
for position in range(0, len(mystring)//2):
# If we've found a mismatched pair of letters, then we can
# stop looking; we know it's not a palindrome.
if mystring[position] != mystring[(-1 * position) - 1]:
print("This is NOT a palindrome")
return # This breaks you out of the entire function.
# If we've gotten this far, then the word must be a palindrome.
print("This is a palindrome")
# Here's where we run the command to input the string, and run the function
mystring = input("Enter your string: ")
is_palindrome(mystring)

Starred expression in ternary operator python

I wrote a python program to print the ascii value of up to every 3 numbers in a string or "ERROR" if the length is not divisible by three. I was golf the code when I ran into a SyntaxError.
Code:
c=input()
p=len(c)
c=[int(c[i:i+3])for i in range(0,len(c),3)]
print("ERROR"if p%3else*map(chr,c),sep='')#SyntaxError here
But this works:
c=input()
p=len(c)
c=[int(c[i:i+3])for i in range(0,len(c),3)]
print(*map(chr,c),sep='')
Putting a space before the * or after the 3 doesn't work. I could just use ''.join but it's one character longer. My question is why can't I use a starred expression in a ternary operator?
Because the * has to apply to the whole expression that produces the set of arguments, not a part of it, and not conditionally. Internally, CPython uses different bytecodes for calling with unpacking vs. normal calls, so your conditional would require it to change the byte code to call print based on the arguments to print, essentially rewriting what you wrote into pseudocode like:
if p % 3:
call(print, "ERROR", sep='')
else:
call_varargs(print, *map(chr, c), sep='')
which is beyond the compiler's capability.
If you wanted to make this work, you could do the following:
print(*(("ERROR",) if p%3 else map(chr,c)), sep='')
which ensures the whole ternary evaluates to an unpackable sequence and unpacks whatever survives unconditionally, avoiding the confusion.
print(*(["ERROR"] if p%3 else map(chr,c)),sep="!")
keep it outside of the ternary
The * expander transforms a single enumerable variable into individual variables. E.g.
li = [1,2,3]
print(*li)
produces: 1 2 3 instead of [1, 2, 3].
One value vs. multiple values
It appears to remove the brackets and pass a single string to print, but this is only an appearance, it actually replaces the single list variable by 3 variables and is actually equivalent to:
print(li[0], li[1], li[2])
It works because print accepts a variable number of arguments, so in our case it can deal with the single list or with these three integers.
The conditional expression is a one-value operator
However in your code you use the star operator within a conditional expression:
c = '065066067068'
p = len(c)
c = [int(c[i:i+3]) for i in range(0, p, 3)]
print('ERROR' if p%3 else *map(chr, c), sep='!')
print would be able to accept both evaluations of the expression, a single string value ('ERROR') or multiple char values from map.
But the conditional expression prevents returning multiple values according to the condition (p%3). The expression output has to be a single value. So you have no other choice than to return the list from map as an enumerable, and un-nest it only outside of the ternary operator, e.g. in the print statement.
A string is an enumerable, not a scalar value
However this solution now introduces another problem: Un-nesting will also convert the constant string ERROR into single chars, as a string is considered by Python an enumerable of single chars (as you know since you use this property for your input string). When the condition is true, the output would be:
E!R!R!O!R
Therefore the string must be first converted to an enumerable of strings, e.g. a tuple
Final solution
if p%3: s = ('ERROR',)
else: s = map(chr, c)
print(*s, sep='!')
The outputs will be:
A!B!C!D
ERROR

using exception with for loop in python

hey guys am new to python app development..i have been trying to fetch only numbers from a list using a for loop..But am confused with the correct syntax..The code i have been used.is like below.
babe = [10,11,13,'vv']
int(honey) [for honey in babe]:
print honey
When i run this i got syntax error.i have tried many situations.But it didnt helped me at all.Sorry for the silly question..
do i wanna add square brackets or something on the second line ??
Am really stuck.Hope you guys can help me out..Thanks in advance
You seem to be conflating the syntax for for loops (a statement followed by a suite of statements ... otherwise known as a "block of code") and a list comprehension (an expression).
Here's a list comprehension:
#!/usr/bin/python
# Given:
b = [1,2,3,'vv']
a = [int(x) for x in b]
... that's syntactically valid. However, the semantics of that example will raise an exception because 'vv' is not a valid literal (string). It cannot be interpreted as a decimal integer.
Here's a for loop:
#!/usr/bin/python
# Given:
b = [1,2,3,'vv']
a = list()
for x in b:
try:
a.append(int(x))
except ValueError:
pass
In this case we explicitly loop over the given list (b) and ignore any ValueError exceptions raised when we try to convert each of those entries into an integer.
There is no reasonable way to handle exceptions from within a list comprehension. You could write a function which returned some sentinel value (from the expression) for any invalid input value. That would look something like this:
#/usr/bin/python
# Given:
b = [1, 2, 3, 'vv']
def mk_integer_if_possible(n):
'''Returns an integer or the sentinel value None
'''
results = None
try:
results = int(n)
except ValueError:
pass
return results
# Use that function:
a = [mk_integer_if_possible(x) for x in b if mk_integer_if_possible(x) is not None]
Note: the absurd function name is deliberate. This is an ugly way to do this and the awkwardness of having to call this putative function TWICE for each element of b is an indication that you should NOT use a list comprehension for this situation. (You have to call it once to make the conversion but again for the conditional. Saving the results from one call would, of course, be a STATEMENT, which we can't have embedded within an EXPRESSION).
Statements contain one or more expressions. Expressions are components of statements. Python strictly delineates between statements and expressions. Assignments are statements in Python. These distinctions can be nuanced and there are other programming languages where assignments are expressions rather than being strictly defined, by the language's syntax, as statements.
So, use the for loop whenever you have to handle possible exceptions while iterating over any sort of data set and usually when you need to filter on the results generated by mapping a function over a list comprehension.
Incidentally the explicit use of the expression is not None is necessary in this example. If I attempted to shorten that test to simply be if mk_integer_if_possible(x) using Python's implicit boolean handling then we'd be inadvertently filtering out any entries from b that evaluated to integer 0 as well as any that were returned as the None sentinel by my ill-advised function.
In Python it's often fine to use implicit boolean values as conditions. None and False as well as any numerically zero value, any empty string or any sort of empty list, tuple or dictionary, are all treated as "false" in a boolean context. However, when dealing with sentinel values it's best to use the is operator and explicitly test for object identity. Otherwise you'll have corner cases where your condition might be matched by values other than your sentinel.
(Handy trick: if you ever come across the need to allow None through some sort of filter or pass it along, but you need some other sentinel ... just use sentinel = object() ... you can create (instantiate) a generic Pythonobject and use is to match it for your sentinel handling. That will be unique to your code and no other Python object or type will match it. Guaranteed).
By the way ... I should note that this code it technically not "fetching only numbers from a list." It is returning integers for all entries in the list which can be converted thereto. This is a nitpick; but it's a distinction that any good engineer will notice. Do you want to return all integers from the input list? Or do you want to return all entries as integers if that can be so converted? Your code suggested that you're trying to accomplish the latter; so that's how I implemented my working examples for you. However, to implement the later semantics you'd probably want to use either the (mathematical) additive or multiplicative identity property like so:
# ... from within some function:
try:
results = x == x + 0 # Additive identity
except (TypeError, ValueError):
results = None
return results
babe = [10,11,13,'vv']
a = [honey for honey in babe if isinstance(honey, int)]
print a
See more here about list comprehension: https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions

Boolean expression in Python or a string? Always returns 'True'

I'm trying to build a Boolean expression, based on (unpredictable) user input. I find that I'm building a string that looks proper, but doesn't work. I've looked at python.org, Google and Stackoverflow and couldn't find what goes wrong here.
Example of the code:
print stringDing
newVariable = stringDing.replace('False','0')
print newVariable
print bool(newVariable)
Output from this:
False or False or False
0 or 0 or 0
True
Yet when the string is pasted into python, python responds as expected:
>>> False or False or False
False
I think I need to build this as a string because the user can add 'OR', 'AND' and brackets, which I would need to fit in at the proper place.
How to proceed?
Interpreting a non-empty string as bool will always evaluate to True. I.e.:
print bool("False") # True
print bool("0") # True
This is, because a str is an iterable object (such as list, set or dict). All iterable objects are considered to be True, if they are non-empty. A str is an iterable, that iterates over its characters. This is useful, e.g. if you want to test if a string s is empty. In such a case you can just write:
if s:
# do something with non-empty string s.
However, if you want to evaluate the expression that is represented by the string, then call eval:
print eval("False") # False
print eval("0") # 0
print bool(eval("0")) # False
If you want to evaluate the way it is evaluated at the python prompt, you can just do eval(stringDing). If it is a logical expression, it will return a bool.

Using "and" in return

I'm taking Web Application Engineering course on Udacity. I noticed that the instructor use and operator in return statement in his validation method. And I didn't understand how it is possible to return 2 arguments. I think, it may be something like if statement. Could anyone explain what it actually is?
Here is the validation method:
USER_RE = re.compile(r"^[a-zA-Z0-9_-]{3,20}$")
def valid_username(username):
return username and USER_RE.match(username)
Thanks in advance.
The and operator evaluates whether both of its arguments are tru-ish, but in a slightly surprising way: First it examines its left argument. If it is truish, then it returns its right argument. If the left argument is falsish, then it returns the left argument.
So the last line in your code:
return username and USER_RE.match(username)
is the same as:
if username:
return USER_RE.match(username)
else:
return username
Strings like username are truish if they are not empty. The regex match function returns a truish match object if the pattern matches, and returns None, a falsish value, if it doesn't match.
The net result is that valid_username will return a truish value if username is not an empty string, and the username matches the given pattern.
Note the "and" here has nothing to do with returning two values, it's computing one value.
When you use a logical operator, it continues according to the rules, so with and, it evaluates the truthiness of the first statement and if it isn't truthy, it returns a non-truthy value (in the first case, '').
print repr("" and "THIS IS POST AND")
""
print "" or "THIS IS POST AND"
THIS IS POST AND
print None or "Something else"
Something else
Where this comes in handy is when you don't want to call a non-existent method on something like None (e.g. the length trait):
r = None
s = [1,2,3,4]
print r and len(r)
None
print s and len(s)
4
In the case you posted, the point is that you only want to check the username against the regular expression if the username is truthy.
It's important to note here that and, and or both short-circuit. So if you get something non-truthy, the function won't even evaluate the regular expression.
and is just a binary operator. return a and b is structurally the same as return a + b or return a * b, and works the same way. The expression is evaluated, then its result is given to return, which returns it to the caller. There is nothing at all special about using and in a return statement.
As explained very well by Ned's answer, the result of a and b is true-ish if both of a and b are true-ish, and false-ish otherwise. It also short-circuits if the left argument is false-ish, since that is sufficient to determine the result of the whole a and b expression.
In this case, an empty string would not match that regular expression, so the operation is redundant considered purely as logic. I strongly suspect though that it's being used here because username might be given the value None, which would cause the regular expression match to throw an exception. Using username and USER_RE.match(username) rather than just USER_RE.match(username) means that any false-ish value (including None) for username causes the function to return something false-ish without even attempting the regular-expression match.
But again, this has nothing to do with return, it's just how and works.

Categories