Starred expression in ternary operator python - 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

Related

Remove else statement from list comprehensions

Why won't it not, not letting me use a else statement? When I run this code it's giving me this error SyntaxError: expected 'else' after 'if' expression, but I simply don't want to return anything after the if statement
x = ["x" if "x" in letter for letter in s]
It looks like what you want to do is to filter the list, rather than to map each value to a different value. The syntax for that is to place an if clause at the end of the list comprehension:
["x" for letter in s if "x" in letter]
At this position in a list comprehension, if has a special meaning: the subsequent expression is used for filtering, so that the comprehension returns only those elements that satisfy the condition (and there can be no else). The condition is evaluated with the original value of the item, but you can still do mapping (as you do, since you're using "x" instead of letter).
In your original attempt, you used if in the mapping expression (which says what you want each result element to be). There, it is interpreted as a conditional expression that must have an else.
By the way, if s is a string, so that letter is a single-character string, you should use letter == "x" instead of "x" in letter. The latter works, but kinda by accident (because Python represents individual characters as strings with length one), and looks confusing because the right hand side of in is usually a "full" string or a collection.
Two main parts of list comprehensions are : condition part and expression part.
Here is the syntax:
[expression for member in iterable if condition]
in condition part, you can not use else. Think of it as a filter. Move it to the end so that it acts like a filter:
x = ["x" for letter in s if "x" in letter]
But in expression part you can have any valid Python expression.
for example a conditional expression as the expression part which is:
a = <on_true> if <condition> else <on_false>
So you need to have the else part in expression part of the list comprehension because the expression part is indeed a conditional expression and the conditional expression need else.

Calling function on result of operator expression? (mask == instance_id).astype(np.uint8)

I am used to seeing parenthesis instantiate a tuple when they are wrapped around an expression. But in this code it looks like they instead allow a function to be invoked on the result of the operator expression:
img = np.random.rand(100,100)
img = img * 100
img = np.round(img)
val = 15
binary_mask = (val == i).astype(np.uint8)
Can someone explain the last line of this code? Why is (val == i) not being interpreted as a tuple?
To get Python to realise that an expression within parentheses is intended as a tuple with one element, you need to put the , after it:
binary_mask = (val == i,).astype(np.uint8)
Otherwise it's simply interpreted as a parenthesised expression. (Such a string of characters is ambiguous, so Python naturally parses it the way it's most commonly intended, as well as giving you an explicit way to indicated the other.)
To support the above with a quote from the Python docs
A special problem is the construction of tuples containing 0 or 1 items: the
syntax has some extra quirks to accommodate these. Empty tuples are
constructed by an empty pair of parentheses; a tuple with one item is
constructed by following a value with a comma (it is not sufficient to enclose
a single value in parentheses). Ugly, but effective.

Strange python syntax, or in print statement

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)

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

Display the number of lower case letters in a string

This is what I have so far:
count=0
mystring=input("enter")
for ch in mystring:
if mystring.lower():
count+=1
print(count)
I figured out how to make a program that displays the number of lower case letters in a string, but it requires that I list each letter individually: if ch=='a' or ch=='b' or ch=='c', etc. I am trying to figure out how to use a command to do so.
This sounds like homework! Anway, this is a fun way of doing it:
#the operator module contains functions that can be used like
#their operator counter parts. The eq function works like the
#'=' operator; it takes two arguments and test them for equality.
from operator import eq
#I want to give a warning about the input function. In python2
#the equivalent function is called raw_input. python2's input
#function is very different, and in this case would require you
#to add quotes around strings. I mention this in case you have
#been manually adding quotes if you are testing in both 2 and 3.
mystring = input('enter')
#So what this line below does is a little different in python 2 vs 3,
#but comes to the same result in each.
#First, map is a function that takes a function as its first argument,
#and applies that to each element of the rest of the arguments, which
#are all sequences. Since eq is a function of two arguments, you can
#use map to apply it to the corresponding elements in two sequences.
#in python2, map returns a list of the elements. In python3, map
#returns a map object, which uses a 'lazy' evaluation of the function
#you give on the sequence elements. This means that the function isn't
#actually used until each item of the result is needed. The 'sum' function
#takes a sequence of values and adds them up. The results of eq are all
#True or False, which are really just special names for 1 and 0 respectively.
#Adding them up is the same as adding up a sequence of 1s and 0s.
#so, map is using eq to check each element of two strings (i.e. each letter)
#for equality. mystring.lower() is a copy of mystring with all the letters
#lowercase. sum adds up all the Trues to get the answer you want.
sum(map(eq, mystring, mystring.lower()))
or the one-liner:
#What I am doing here is using a generator expression.
#I think reading it is the best way to understand what is happening.
#For every letter in the input string, check if it is lower, and pass
#that result to sum. sum sees this like any other sequence, but this sequence
#is also 'lazy,' each element is generated as you need it, and it isn't
#stored anywhere. The results are just given to sum.
sum(c.islower() for c in input('enter: '))
You have a typo in your code. Instead of:
if my.string.lower():
It should be:
if ch.islower():
If you have any questions ask below. Good luck!
I'm not sure if this will handle UTF or special characters very nicely but should work for at least ASCII in Python3, using the islower() function.
count=0
mystring=input("enter:")
for ch in mystring:
if ch.islower():
count+=1
print(count)
The correct version of your code would be:
count=0
mystring=input("enter")
for ch in mystring:
if ch.islower():
count += 1
print(count)
The method lower converts a string/char to lowercase. Here you want to know if it IS lowercase (you want a boolean), so you need islower.
Tip: With a bit of wizardry you can even write this:
mystring= input("enter")
count = sum(map(lambda x: x.islower(), mystring))
or
count = sum([x.islower() for x in mystring])
(True is automatically converted to 1 and False to 0)
:)
I think you can use following method:
mystring=input("enter:")
[char.lower() for char in mystring].count( True ) )

Categories