Reputation: 25219
Let's say I have a rather contrived example like:
X = {'a':True, 'b':False}
x = ("a","and","b")
y = ("a","or","b")
def func(z):
return X[z[0]] 'and/or' X[z[2]]
Is there a fast way to construct such a logic:
eval
, because it's a significant overhead for a function evaluated in a loop ~1e6 timesif/else
logic because it again will add overhead and real logic could be lengthy?Upvotes: 1
Views: 87
Reputation: 71461
You can use operator
with recursion to handle arbitrary expression strings:
import operator
X = {'a':True, 'b':False}
def _eval(s):
l, o = None, None
while (n:=next(s, None)) not in {')', None}:
if n in {'and', 'or'}:
o = n
else:
v = n if n != '(' else _eval(s)
if l is None:
l = v
else:
s = iter([getattr(operator, f'{o}_')(X.get(l, l), X.get(v, v)), *s])
l, o = None, None
return l
import re
def run_eval(s):
return _eval(iter(re.findall('\(|\)|\w+', s)))
print(run_eval('a and b'))
print(run_eval('a or b'))
print(run_eval('a and (b or (a and b)) or b'))
Output:
False
True
False
Edit: evaluating tuple-based input:
from collections import deque
X = {'a':True, 'b':False, 'c':True}
def _eval(t):
d = deque(t) #using deque for faster element removal and addition
while len(d) > 1:
a, b, c = [d.popleft() for _ in range(3)]
v1, v2 = X[a] if a in X else (a if not isinstance(a, tuple) else _eval(a)), X[c] if c in X else (c if not isinstance(c, tuple) else _eval(c))
d.appendleft(getattr(operator, f'{b}_')(v1, v2))
return d[0]
def run_eval(t):
return _eval(t)
print(run_eval(("a", "and","b")))
print(run_eval(("a", "or","b", "or", "c")))
print(run_eval((("a","and","b"), "or",("a","and","b"))))
Output:
False
True
False
Upvotes: 3
Reputation: 2343
You can make use of the built-in operator library. Something like below:
>>> X
{'a': True, 'b': False}
>>> mapping
{'and': <built-in function and_>}
>>>
>>> def f(z):
... return mapping[z[1]](X[z[0]],X[z[2]])
...
>>> f('a and b'.split())
False
>>> f('a and a'.split())
True
>>>
Upvotes: 1