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.
Related
I'm pretty new to Python and have written a function that has 5 arguments:
def function(a,b,c,d=False,e=" "):
Argument d can either be true or false. If false, then the default value for e will be white space, and we wouldn't need to pass this into the function when calling it, if true, then we can either pass an argument to e, or leave it blank.
function(a,b,c,False) #Example 1: d==False
function(a,b,c,True,'*') #Example 2: d==True, then pass value to e to override default
My issue, however, lies with the following example:
function(a,b,c,True) #Example 3: d==True but no value passed to e
If d is true and no value is passed to argument e, I want to change the default value of e to something else. I only want to do this in instances where d==True and e isn't passed. Basically, I want the default behaviour of argument e to be dependent on the boolean value of d:
def function(a,b,c,d=False,e=" " if d==False, '*' if d=True)
Basically, I want two default states for argument e, dependent on whether argument d is True or False.
Is this possible?
Use a None value for e and adjust if not passed
def function(a,b,c,d=False,e=None):
if e is None:
e="*" if d else ' '
pass
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.
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.
Is there an operator or a library function such that v ??? d
evaluates to v if v is distinct from None and doesn't evaluate d, or
evaluates to d if v is equal to None.
(where by ??? I denote the operator I'm seeking).
Operator or is almost what I want, but it evaluates to the default value if v is False. I want the default only if the argument is None, so that False ??? d evaluates to False.
Update: To clarify, in my case v can be a complex expression, like computeSomethingLong() ??? d. So I can't use
computeSomethingLong() if computeSomethingLong() is not None else d
I'd have to do something like
tempvar = computeSomethingLong()
tempvar if tempvar is not None else d
which feels quite awkward, compared to computeSomethingLong() or d.
Update: The closest I got is to define my own function:
def orElse(v, deflt):
if v is not None:
v
else:
deflt
But the drawback is that deflt is always evaluated! I want it to evaluate only if it's actually needed. In particular, I want that in
firstLongComputation() ??? secondLongComputation()
the first computation is evaluated; if it's result is not None, it is returned. Otherwise the second one is evalauted (and only in this case) and it will be the result of the expression.
There's no such operator, but it's straigtforward anyway using ternary if "operator"
v if v is not None else d
If v is an expensive function call, you can employ any kind of caching (aka memoization) to still use the same approach:
#memoize
def computeSomethingLong():
"""whatever"""
computeSomethingLong() if computeSomethingLong() else computeSomethingElse()
Will still evaluate computeSomethingLong once.
See python manual or some other instructions for details on decorators.
Try with v if v is not None else d
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"!-)