Nested conditions in python - python

I am trying to figure out the shortest, most pythonic way to implement a similar to the following syntax:
if A and (B if C):
print(A)
in a way that:
if C is False, then B is omitted (therefore (B if C) is True).
if C is True, then B is evaluated, effectively making the syntax if A and B:
This can be made through various separate if statements, but my ultimate purpose with this was to make it into a list comprehension for a value assignment.
Edit:
The list comprehension I wanted to make was this:
methods = [name for (name, func) in locals().items() \
if callable(func) and (not __name__ == '__main__' or \
func.__module__ == __name__)]
So that it returns the function names I have defined in that module as well as if methods is imported from the outside.

This should be equivalent, if my old statement logic doesn't fail me =)
if A and (not C or B):
print(A)
Explanation: "B if C" <=> C -> B <=> not C or B
Expression B is only evaluated if C holds.

your hypothesis:
if C is False, then B is omitted
if C is True, then B is evaluated, effectively making the syntax if A and B:
wouldn't that be:
if A and (not C or B):
print(A)
if C is false then not C is True and we don't evaluate B
if C is true, then not C is False, and we have to evaluate B

Your if pseudo-operator is just logical implication, where
C -> B = not C or B
This means you just want
if A and (not C or B):
When C is False, A and (not C or B) == A and (True or B) == A and True == A.
When C is True, A and (not C or B) == A and (False or B) == A and B.

This:
if A and (B if C else True):
pass
is closest to your "pseudo code", using the conditional expression x if cond else y in Python. Assuming B=True in case C is False effectively make the if statement consider only the boolean value of A

I'd probably write it like this:
condition = (A and B) if C else A
if condition:
print(A)
I've only broken the condition into a separate variable because I think mixing an if with a Python conditional expression looks a little confusing. You'll have to make a call whether it looks confusing when used inside a list comprehension or not.

Related

Assigning an OR statement to a variable in python

I have been looking for ways to assign a or statement to a variable, in a way that the variable can be used as a reference for other comparisons.
What i'm trying to accomplish by example:
a = 1
b = 0
c = a or b
print(a == c) #would return True
print(b == c) #would also return True
What you seem to want is somewhat close to the way sets work, with the operator | replacing or (which cannot be overridden):
a = {0}
b = {1}
c = a | b # or a.union(b)
a.issubset(c) # True
b.issubset(c) # True
{3}.issubset(c) # False
You could in principle make your own class that extends set:
class Singleton(set):
def __init__(self, n):
super().__init__([n])
def __eq__(self, other):
return self.issubset(other) or other.issubset(self)
a = Singleton(1)
b = Singleton(0)
c = a | b
print(a == c) # True
print(b == c) # True
But it is doubtful whether the confusing code this generates would ever be worth it.
You can change the definition of the == operator by creating a class and replacing your integer values with objects that contain each integer, so you will be able to override the equal operator with the __eq__ function. In this example, I will negate the result of the default operator to show you that you can apply whatever definition you need for that operation. The only disadvantage is that in Python, you can't override or redefine or:
class num:
def __init__(self, n):
self.n = n
def __eq__(self, n):
return not n==self.n
a = num(1)
b = num(0)
c = a or b
print(a == c)
print(b == c)
You can get something like that by using functools.partial and operator.or_:
a=True
b=False
c = partial(or_, a,b)
c()
True
But beware, a and b are evaluated at definition time:
a=False
c()
True

python convert a string to a logic gate function

I have a python string like: "(a and b and c) or (d and e)", where a, b, c, d and e are conditions of some kind. As you can probably see, this is actually a logical expression.
I'd like to somehow convert it into a logic-gate-like function, say, f. So I would pass a number of true conditions to f, and get the logical results. Examples:
If I pass it (d and e) (i.e., d and c are true), f returns True.
If I pass it (a and b and c), f returns True.
If I pass it just a, f returns False.
If I pass it just b and c, f returns False.
I have no idea how to tackle such a question. strtobool doesn't quite handle my requirements, and I'm not sure how to even convert the given string into a function. As for passing it true conditions as input, I'm thinking of passing it a list of True booleans, i.e. all conditions are False by default. e.g. from the first example above:
d = True; e = True
f([d, e])
> True
d = True; e = False
f([d])
> False
You're looking for eval.
Essentially, you can do-
eval('d and e', {'d': True, 'e': False})
Which passes the d and e string to evaluate, and also passes in some globals, to set the value of those variables.
It's often better to use the third argument, locals, instead of globals however.
eval('d and e', {}, {'d': True, 'e': False})
This will achieve the same thing, except d and e are set in local scope, the second argument is just empty.

Defining Functions in Z3Py that return true for some inputs and false for others

I am trying to define a function that will return true if two objects are connected and false otherwise.
In the example (cf. picture), where node a is connected to node b and c but there is no connection between b and c I want the function to behave like that:
connected(a, b) = true
connected(a, c) = true
connected(b, c) = false
So my question can be divided in two sub-questions:
a) How would i define such a function generally with the python api of Z3 (z3py), considering, that i would provide all possible assignments for the function upfront.
b) is it possible to define a funciton in a way, that I only provide the cases, where the function evaluates to true (i.e. only for the connected nodes) and then say somehow, that this function should evaluate to false in all other cases.
Sure:
from z3 import *
Object, (a, b, c) = EnumSort('Object', ('a', 'b', 'c'))
connections = [(a, b), (a, c)]
def isConnected(x, y):
return Or([And(x == i, y == j) for (i, j) in connections])
s = Solver()
s.add(isConnected(a, b))
s.add(isConnected(a, c))
print(s.check())
s.add(isConnected(b, c))
print(s.check())
The first print will say sat, and the second will say unsat, since b and c are not connected.
You can easily generalize this to any number of objects. Or even do things like:
s = Solver()
p = Const('p', Object)
q = Const('q', Object)
s.add(isConnected(p, q))
print(s.check())
print(s.model())
which will print:
sat
[q = b, p = a]
but note that this assignment will never contain the pair b, c as requested.
alias is right, you can simply declare the signature of the function and the implementation as you please. In other words, the evaluation of the function is up to you to assert.

Python declarative loop refactor (need access multiple elements)

Hi I have this piece of code and trying to refactor it to be declarative. But AFAIK, all declarative methods like map() reduce() filter() will loop through each element of the container, not a few like this
def arrayCheck(nums):
# Note: iterate with length-2, so can use i+1 and i+2 in the loop
for i in range(len(nums)-2):
# Check in sets of 3 if we have 1,2,3 in a row
if nums[i]==1 and nums[i+1]==2 and nums[i+2]==3:
return True
return False
So how to write this code, declarative way?
First, you can use a zip to rewrite your loop:
def array_check(nums):
for a, b, c in zip(nums, nums[1:], nums[2:]):
if a == 1 and b == 2 and c == 3:
return True
return False
Then, use the tuple comparison:
def array_check(nums):
for a, b, c in zip(nums, nums[1:], nums[2:]):
if (a, b, c) == (1, 2, 3):
return True
return False
And then the any builtin:
def array_check(nums):
return any((a, b, c) == (1, 2, 3) for a, b, c in zip(nums, nums[1:], nums[2:]))
Test:
>>> array_check([1,3,4,1,2,3,5])
True
>>> array_check([1,3,4,1,3,5])
False
Note: for a faster version, see #juanpa.arrivillaga comment below.
If you want to mimic functional style:
import operator, functools
def array_check(nums):
return any(map(functools.partial(operator.eq, (1,2,3)), zip(nums, nums[1:], nums[2:])))
But that's really unpythonic!

Pythonic way to select first variable that evaluates to True

I have some variables and I want to select the first one that evaluates to True, or else return a default value.
For instance I have a, b, and c. My existing code:
result = a if a else (b if b else (c if c else default))
Another approach I was considering:
result = ([v for v in (a, b, c) if v] + [default])[0]
But they both feel messy, so is there a more Pythonic way?
Did you mean returning first value for what bool(value)==True? Then you can just rely on the fact that boolean operators return last evaluated argument:
result = a or b or c or default
If one variable is not "defined", you can't access its name. So any reference to 'a' raises a NameError Exception.
In the other hand, if you have something like:
a = None
b = None
c = 3
you can do
default = 1
r = a or b or c or default
# r value is 3
So long as default evaluates to True:
result = next((x for x in (a, b, c, d , e, default) if x))
You could do something like this (in contrast to the other answers this is a solution where you don't have to define the 'missing' values as being either None or False):
b = 6
c = 8
def first_defined(items):
for x in items:
try:
return globals()[x]
break
except KeyError:
continue
print first_defined(["a", "b", "c"])
In order to avoid NameErrors when a, b or c isn't defined: give the function a list of strings instead of variable references (you can't pass non-existing references). If you are using variables outside the 'globals()' scope, you could use getattr with its default argument.
--
If a, b and c are defined, I'd go for something like this (considering the fact that an empty string, None or False evaluate to a boolean False):
a = None
b = 6
c = 8
def firstitem(items):
for x in items:
if x:
return x
break
else:
continue
print firstitem([a, b, c])
Don't know if this works in every case, but this works for this case.
a = False
b = "b"
c = False
default = "default"
print a or b or c or default # b
How about this ?
a=None
b=None
c=None
val= reduce(lambda x,y:x or y,(a,b,c,"default"))
print val
The above prints "default". If any of the inputs is defined, val would contain the first defined input.
If by defined you mean ever assigned any value whatsoever to in any scope accessible from here, then trying to access an "undefined" variable will raise a NameError exception (or some subclass thereof, but catching NameError will catch the subclass too). So, the simplest way to perform, literally, the absolutely weird task you ask about, is:
for varname in ('a', 'b', 'c'):
try: return eval(varname)
except NameError: pass
return default
Any alleged solution lacking a try/except won't work under the above meaning for "defined". Approaches based on exploring specific scopes will either miss other scopes, or be quite complex by trying to replicate the scope-ordering logic that eval does for you so simply.
If by "defined" you actually mean "assigned a value that evaluates to true (as opposed to false)", i.e., all values are actually defined (but might happen to be false, and you want the first true value instead), then the already-proposed a or b or c or default becomes the simplest approach. But that's a totally different (and even weirder!) meaning for the word "defined"!-)

Categories

Resources