Conditional expression/ternary operator - python

I don't understand this syntax.
Python program to demonstrate ternary operator
a, b = 10, 20
Use tuple for selecting an item
print( (b, a) [a < b] )
Use Dictionary for selecting an item
print({True: a, False: b} [a < b])
PS: I guess this is from older version of Python, because in newer versions (don't know from which version) True and False are reserved keywords, so they can't be assigned a value.
lamda is more efficient than above two methods
because in lambda we are assure that only one expression will be evaluated unlike in
tuple and Dictionary
print((lambda: b, lambda: a)[a < b]())
Syntax should be:
[on_true] if [expression] else [on_false]
So how does
print( (b, a) [a < b] )
print({True: a, False: b} [a < b])
print((lambda: b, lambda: a)[a < b]())
fit this syntax?
What's the meaning of [a<b] after tuple/dictionary/lambda? I have never seen this syntax before. It also works when list [b, a] precedes [a<b].
I would expect it to look like this
print( a if a < b else b )
Link to resource:
https://www.geeksforgeeks.org/ternary-operator-in-python/

First note that all these give the minimum value of a and b:
a, b = 10, 20
res1 = (b, a)[a < b] # 10
res2 = {True: a, False: b}[a < b] # 10
res3 = (lambda: b, lambda: a)[a < b]() # 10
We can consider these in turn:
res1 constructs a tuple of 2 integers. a < b returns a Boolean value, in this case True. In Python, True == 1, as bool is a subclass of int. Finally, [] is syntactic sugar for __getitem__, which is the method called for positional indexing. Since Python starts counting from 0, the first index is a. You can also confirm this yourself: (b, a).__getitem__(1) returns 10.
res2 constructs a dictionary mapping Boolean values to a & b. Calling __getitem__ on a dict object returns the value for a given key. Here the key, as before, is True. Since the dictionary maps True to a, this is the value returned.
res3 constructs a tuple of anonymous (lambda) functions, each returning scalars, namely b and a. As per res1, an item can be extracted from a tuple via integer indexing. The only additional requirement is to actually call the lambda functions via ().
Note none of these operate the same way as the ternary operator which is applied at compile time (see comments) via an in-line if / else:
res4 = a if a < b else b

a<b is a bool (True or False). Since bool is a subtype of int, it can be used in a context where an integer is expected, e.g. as a list/tuple index:
>>> True == 1
True
>>> False == 0
True
>>> isinstance(True, int)
True
>>> ('a', 'b')[True] # True == 1
'b'
>>> ('a', 'b')[1<2] # 1<2 == True == 1
'b'
>>> ('a', 'b')[2<1] # 2<1 == False == 0
'a'
For dict keys, it is similar, but the type coercion is not even needed:
>>> {True: 'a', False: 'b'}[1<2] # 1<2 == True
'a'

Your misconception might be regarding a < b .
In all these cases the boolean result of evaluating a < b is used as a key for the object in before.
In the case of
print( (b, a) [a < b] )
and
print((lambda: b, lambda: a)[a < b]())
the object is a tuple containing either the variables themselves or very simple anonymus functions, that return these variables.
In the case of
print({True: a, False: b} [a < b])
the expression is evaluated and used as a key for the dictionary, which has both True and False as keys. The assumption that this means, that it must be an older Python version is incorrect thoug, because a dictionary does not represent a reassignment of values, but is merely a data structure, where a key maps to a value. True and False are valid keys and this circumstance is precisely, what is being used here.
Finally:
print( a if a < b else b )
Is a nice and concise may of expressing the same thing and in fact the line of code I would use in this case

Related

Determine relevant parts of a boolean expression that cause evaluation to True

Given that I have boolean expressions which I know will evaluate to True that have a number of variables (1...n) and I also know that (1...n) of the variables are True, how can I determine which of the True values actually had an impact on the expression (i.e. causing it to evaluate it to True)?
Basic example: let's assume I have (A and B) or (C and D) with A = True, B = True and C = True. In this case the value of C is irrelevant for the evaluation of the boolean expression as the right part of the expression always evaluates to false given D = False.
I would need a method (e.g. find_relevant_values()) to determine that [A, B] are relevant.
A = True
B = True
C = True
D = False
bool_exp = "(A and B) or (C and D)"
print(eval(bool_exp)) #True
# is this doable?
print(find_relevant_values(bool_exp)) #[A, B]
I would need a generic way (e.g. find_relevant_values()) to determine the relevant values. In the example above [A, B] are the relevant values.
The solution below works in three steps: First, the input string is parsed to generate an expression tree. Second, the tree is traversed to find any instances of an or operator. If any of the or operands evaluate to True, the operand is either yielded if it is a terminal value (A, B, C, or D) or recursively traversed by find_relevant. Lastly, if no or operators are found, then the entire expression is evaluated and if the result is True, then the tree is traversed for all the relevant expressions that triggered the True value:
import re, collections as cl
m, op = {'A':True, 'B':True, 'C':True, 'D':False}, {'or':lambda x, y:x or y, 'and':lambda x, y:x and y}
#create the expression tree
def parse_expr(d):
while (n:=next(d, None)) not in {None, ')'}:
if n != '(':
yield n
else:
yield list(parse_expr(d))
#evaluate the tree
def rel_eval(expr):
while len(expr) > 1:
_a, b, _c = [expr.popleft() for _ in range(3)]
a = m.get(_a, _a) if not isinstance(_a, list) else rel_eval(collections.deque(_a))
c = m.get(_c, _c) if not isinstance(_c, list) else rel_eval(collections.deque(_c))
expr.appendleft(op[b](a, c))
return expr[0]
#search for the relevant parts of the expression
def find_relevant(d):
f = False
for i in range(len(d)-1):
if d[i] == 'or':
f = True
if (isinstance(d[i-1], list) and rel_eval(cl.deque(d[i-1]))) or (not isinstance(d[i-1], list) and m.get(d[i-1], False)):
yield from ([d[i-1]] if not isinstance(d[i-1], list) else find_relevant(d[i-1]))
break
elif (isinstance(d[i+1], list) and rel_eval(cl.deque(d[i+1]))) or (not isinstance(d[i+1], list) and m.get(d[i+1], False)):
yield from ([d[i+1]] if not isinstance(d[i+1], list) else find_relevant(d[i+1]))
break
if not f and rel_eval(cl.deque(d)):
for i in filter(lambda x:x != 'and' and x != 'or', d):
yield from ([i] if not isinstance(i, list) else find_relevant(i))
Putting it all together:
def find_relevant_values(s):
#parse the input and create the tree
r = list(parse_expr(iter(re.findall('\(|\)|\w+', s))))
#consume the generator results from find_revelant
return list(find_relevant(r))
print(find_relevant_values('(A and B) or (C and D)'))
print(find_relevant_values('(A and (B or C)) and (C or D)'))
Output:
['A', 'B']
['A', 'B', 'C']

Python: Check if a nested list is in a nested list

Sorry for for the potentially silly question. But this seems to be a stumping problem I just can't find the answer to.
Say I have the following mixed nested list in python:
a = [((1,1),(0,0)), (3,4)]
I'd like to check if the following tuples b, c and d appear in a:
b = (1,1)
c = (0,0)
d = (3,4)
print(b in a) # <- False ?
print(c in a) # <- False ?
print(d in a) # <- True
I'd like to replace the code in each print statement in such away that the search finds the tuple in the list and as such returns True
Any help at all would be much appreciated. Apologies if this question has already been asked before.
We need a recursive function that takes a list or tuple and an element to find.
Each function should check whether the element is in the current iterable using the in operator. If it is in then return True, otherwise check if it is in any of the lower dimensions by recursively calling itself with each of the lower iterables and return if any of those succeeded (this can be done with a for-loop, but we may as well use the any() function).
So a one liner would be roughly:
def inc(it, e):
return True if e in it else any(inc(iit, e) for iit in it if type(iit) in (list, tuple))
And it works as intended:
>>> inc(a, (1,1))
True
>>> inc(a, (0,0))
True
>>> inc(a, (3,4))
True
The list has two elements, a tuple which contains other tuples, and a tuple of ints. If you want to check the nested structures, you are going to have to do that yourself. A recursive solution (this one assumes the nested containers can only be either tuple's or lists) would be one option if nesting can be arbitrarily deep:
>>> a = [((1,1),(0,0)), (3,4)]
>>> def is_in(x, nested):
... result = False
... if not isinstance(nested, (tuple, list)):
... return result
... for item in nested:
... if x == item:
... result = True
... else:
... result = result or is_in(x, item)
... if result:
... return True
... return result
...
>>> is_in((1,1), a)
True
>>> is_in((0,0), a)
True
>>> is_in((3,4), a)
True
>>> is_in((8, 8), a)
False
>
This should stop traversing once the first match is found.
Note, if recursion isn't your thing, you can replace the call stack with your own stack!
def is_in_iterative(x, nested):
stack = [nested]
while stack:
item = stack.pop()
print(item)
if item == x:
return True
elif isinstance(item, (list, tuple)):
stack.extend(item)
return False
However, note that this will check in the reverse order...
i tried to solve your problem by recursive function method and global variable defining , i wish this solution can give you idea:
a = [((1,1),(0,0)), (3,4)]
global bb
bb=False
def checker(tuple1, tuple2):
b=str(type(('a','b')))
for i in range(len(tuple1)):
if(str(type(tuple1[i]))!=b):
if (tuple1==tuple2):
global bb
bb=True
else:
checker(tuple1[i],tuple2)
checker(a,(1,1))
print(bb)
#-->True
bb=False
checker(a,(3,4))
print(bb)
#-->True
bb=False
checker(a,(0,0))
print(bb)
#--->True
bb=False
checker(a,(10,1))
print(bb)
#--->False

Python: general iterator or pure function for testing any condition across list

I would like to have a function AllTrue that takes three arguments:
List: a list of values
Function: a function to apply to all values
Condition: something to test against the function's output
and return a boolean of whether or not all values in the list match the criteria.
I can get this to work for basic conditions as follows:
def AllTrue(List, Function = "Boolean", Condition = True):
flag = True
condition = Condition
if Function == "Boolean"
for element in List:
if element != condition:
flag = False
break
else:
Map = map(Function, List)
for m in Map:
if m != condition:
flag = False
break
return flag
Since python doesn't have function meant for explicitly returning if something is True, I just make the default "Boolean". One could clean this up by defining TrueQ to return True if an element is True and then just mapping TrueQ on the List.
The else handles queries like:
l = [[0,1], [2,3,4,5], [6,7], [8,9],[10]]
AllTrue(l, len, 2)
#False
testing if all elements in the list are of length 2. However, it can't handle more complex conditions like >/< or compound conditions like len > 2 and element[0] == 15
How can one do this?
Cleaned up version
def TrueQ(item):
return item == True
def AllTrue(List, Function = TrueQ, Condition = True):
flag = True
condition = Condition
Map = map(Function, List)
for m in Map:
if m != condition:
flag = False
break
return flag
and then just call AllTrue(List,TrueQ)
Python already has built-in the machinery you are trying to build. For example to check if all numbers in a list are even the code could be:
if all(x%2==0 for x in L):
...
if you want to check that all values are "truthy" the code is even simpler:
if all(L):
...
Note that in the first version the code is also "short-circuited", in other words the evaluation stops as soon as the result is known. In:
if all(price(x) > 100 for x in stocks):
...
the function price will be called until the first stock is found with a lower or equal price value. At that point the search will stop because the result is known to be False.
To check that all lengths are 2 in the list L the code is simply:
if all(len(x) == 2 for x in L):
...
i.e. more or less a literal translation of the request. No need to write a function for that.
If this kind of test is a "filter" that you want to pass as a parameter to another function then a lambda may turn out useful:
def search_DB(test):
for record in database:
if test(record):
result.append(record)
...
search_DB(lambda rec: all(len(x) == 2 for x in rec.strings))
I want a function that takes a list, a function, and a condition, and tells me if every element in the list matches the condition. i.e. foo(List, Len, >2)
In Python >2 is written lambda x : x>2.
There is (unfortunately) no metaprogramming facility in Python that would allow to write just >2 or things like ·>2 except using a string literal evaluation with eval and you don't want to do that. Even the standard Python library tried going down that path (see namedtuple implementation in collections) but it's really ugly.
I'm not saying that writing >2 would be a good idea, but that it would be nice to have a way to do that in case it was a good idea. Unfortunately to have decent metaprogramming abilities you need a homoiconic language representing code as data and therefore you would be programming in Lisp or another meta-language, not Python (programming in Lisp would indeed be a good idea, but for reasons unknown to me that approach is still unpopular).
Given that, the function foo to be called like
foo(L, len, lambda x : x > 2)
is just
def foo(L, f=lambda x : x, condition=lambda x: x):
return all(condition(f(x)) for x in L)
but no Python programmer would write such a function, because the original call to foo is actually more code and less clear than inlining it with:
all(len(x) > 2 for x in L)
and requires you to also learn about this thing foo (that does what all and a generator expression would do, just slower, with more code and more obfuscated).
You are reinventing the wheel. Just use something like this:
>>> l = [[0,1], [2,3,4,5], [6,7], [8,9],[10]]
>>> def all_true(iterable, f, condition):
... return all(condition(f(e)) for e in iterable)
...
>>> def cond(x): return x == 2
...
>>> all_true(l, len, cond)
False
You can define a different function to check a different condition:
>>> def cond(x): return x >= 1
...
>>> all_true(l, len, b)
True
>>>
And really, having your own function that does this seems like overkill. For example, to deal with your "complex condition" you could simply do something like:
>>> l = [[0,2],[0,1,2],[0,1,3,4]]
>>> all(len(sub) > 2 and sub[0] == 5 for sub in l)
False
>>> all(len(sub) > 1 and sub[0] == 0 for sub in l)
True
>>>
I think the ideal solution in this case may be:
def AllTrue(List, Test = lambda x:x):
all(Test(x) for x in List)
This thereby allows complex queries like:
l = [[0, 1], [1, 2, 3], [2, 5]]
AllTrue(l, lambda x: len(x) > 2 and x[0] == 1)
To adhere to Juanpa's suggestion, here it is in python naming conventions and an extension of what I posted in the question now with the ability to handle simple conditions like x > value.
from operator import *
all_true(a_list, a_function, an_operator, a_value):
a_map = map(a_function, a_list)
return all( an_operator(m, a_value) for m in a_map)
l = [[0,2],[0,1,2],[0,1,3,4]]
all_true(l, len, gt, 2)
#True
Note: this works for single conditions, but not for complex conditions like
len > 2 and element[0] == 5

Multiple inequality (a < b < c...) with potentially missing value

I would like to test multiple inequalities at once, i.e.
if (a < b < c < ...)
which is fine when all the values are present. However sometimes the numeric value of one or more of the variables to be compared may be missing/unknown; the correct behaviour in my context is to assume the associated inequality is satisfied. Let's say I assign the special value None when the value is unknown: the behaviour I want from the < operator (or an alternative) is:
>>> a = 1; b = 2; c = 3
>>> a < b < c # this works fine, obviously
True
>>> b = None
>>> a < b < c # would like this to return True
False
So I want to get True if one variable is truly smaller than the other, or if one variable is missing (takes any particular pre-decided non-numerical value), or if both variables are missing, and I want to be able to string the comparisons together one go i.e. a < b < c < ...
I would also like to do this with <= as well as <.
Thanks
You want to test if your sequence – bar the undefined values – is in ascending order:
import operator
def isAscending(strictly, *seq):
cmp_op = operator.lt if strictly else operator.le
seq = [e for e in seq if e is not None]
return all(cmp_op(a, b) for a, b in zip(seq, seq[1:]))
a, b, c = 1, None, 2
print isAscending(True, a, b, c) # strictly ascending ?
Edited for spelling, and to use comparison operators as suggested.
This looks like you are actually trying to test if your values are unique and in sorted order which could be replaced by something like:
>>> def my_test(l):
>>> filt_l = [v for v in l if not v is None]
>>> return (sorted(filt_l) == filt_l) and (len(filt_l) == len(set(filt_l)))
>>> my_test([1,2,3])
True
>>> my_test([1,None,3])
True
>>> my_test([1,4,3])
False
>>> my_test([1,1,3])
False
Edit: including timings it seems that the function suggested by sebdelsol is even faster
>>> %timeit isAscending([int(1000*random.random()) for i in xrange(10000)])
100 loops, best of 3: 3.44 ms per loop
>>> %timeit my_test([int(1000*random.random()) for i in xrange(10000)])
100 loops, best of 3: 5.67 ms per loop
You could create your own type overloading comparison methods (as in this question: python overloading operators)
E.g.
class N(object):
def __init__(self, value):
self.value = value
def __lt__(self, other):
return (self.value is None or self.value < other.value)
...
a = N(1); b = N(None); c = N(3)
print a < b < c
If you have your values in a list ([a, b, c]), then you can filter the None values from it, pair them up using zip(), apply the operator to all the pairs and see if all them hold.
In code:
import operator # For operator.lt, which is < ("less than")
def mass_comparify(op, *args):
return all(op(a, b) for a, b in zip(args, args[1:])
if a is not None and b is not None)
print(mass_comparify(operator.lt, 1, None, 3)) # Prints True because 1 < 3
I don't think you have a better option than to define a comparison function which does the comparison as you want, and then write the inequalities as
comp(a,b) and comp(b,c) and ...
I don't know if it fits perfectly, but you can use reduce:
>>> import operator
>>> reduce(operator.__lt__, [1, None, 3])
True
>>> reduce(operator.__lt__, [1, None, 0])
False
or, much more solid, as it explicitly ignores None values:
>>> import operator
>>> reduce(operator.__lt__, filter(None, [1, None, 3]))
True
>>> reduce(operator.__lt__, filter(None, [1, None, 0]))
False

Does Python have an "or equals" function like ||= in Ruby?

If not, what is the best way to do this?
Right now I'm doing (for a django project):
if not 'thing_for_purpose' in request.session:
request.session['thing_for_purpose'] = 5
but its pretty awkward. In Ruby it would be:
request.session['thing_for_purpose'] ||= 5
which is much nicer.
Jon-Eric's answer's is good for dicts, but the title seeks a general equivalent to ruby's ||= operator.
A common way to do something like ||= in Python is
x = x or new_value
Precise answer: No. Python does not have a single built-in operator op that can translate x = x or y into x op y.
But, it almost does. The bitwise or-equals operator (|=) will function as described above if both operands are being treated as booleans, with a caveat. (What's the caveat? Answer is below of course.)
First, the basic demonstration of functionality:
x = True
x
Out[141]: True
x |= True
x
Out[142]: True
x |= False
x
Out[143]: True
x &= False
x
Out[144]: False
x &= True
x
Out[145]: False
x |= False
x
Out[146]: False
x |= True
x
Out[147]: True
The caveat is due python not being strictly-typed, and thus even if the values are being treated as booleans in an expression they will not be short-circuited if given to a bitwise operator. For example, suppose we had a boolean function which clears a list and returns True iff there were elements deleted:
def my_clear_list(lst):
if not lst:
return False
else:
del lst[:]
return True
Now we can see the short-circuited behavior as so:
x = True
lst = [1, 2, 3]
x = x or my_clear_list(lst)
print(x, lst)
Output: True [1, 2, 3]
However, switching the or to a bitwise or (|) removes the short-circuit, so the function my_clear_list executes.
x = True
lst = [1, 2, 3]
x = x | my_clear_list(lst)
print(x, lst)
Output: True []
Above, x = x | my_clear_list(lst) is equivalent to x |= my_clear_list(lst).
dict has setdefault().
So if request.session is a dict:
request.session.setdefault('thing_for_purpose', 5)
Setting a default makes sense if you're doing it in a middleware or something, but if you need a default value in the context of one request:
request.session.get('thing_for_purpose', 5) # gets a default
bonus: here's how to really do an ||= in Python.
def test_function(self, d=None):
'a simple test function'
d = d or {}
# ... do things with d and return ...
In general, you can use dict[key] = dict.get(key, 0) + val.

Categories