N. Chalifour N. Chalifour - 3 months ago 6
Python Question

Checking if the value of a string is true - python

I am trying to see if a string is true or false but im stuck... In the following code I have made a list of statements that I want to evaluate, I have put them in strings because the variables need to be declared after the list is .(Reason is that the list of statements to be evaluated are being passed as a parameter to a function, in this function the variables are declared) I want to run through all of the items in the list and if it is a true statement then do something... Here is my code: (There is no output generated)

a = ['b > c', 'b = c', 'b < c']

b = 5
c = 3

for item in a:
if exec(item):
print(item)

Answer

exec is a function in python3.x1 that returns None so you'll always have a falsy result. You probably want eval.

Also be careful here. Do not use this unless you completely trust the input strings as it will allow execution of arbitrary code otherwise.


Note that this is a very strange code design and there is probably a better way to accomplish what you want... For example:

Why do you want to define the strings before the variables are defined? Coupling strings to names in your code in this way is likely to lead to a painful code maintenance experience.

1In python2.x, this would fail with a SyntaxError since exec was a statement prior to python3.x


Having tried to understand your use-case a little more, I would propose that you create an API where you pass functions.

def f1(a, b, **kwargs):
    return a > b

def f2(a, b, **kwargs):
    return a == b

def f3(a, c, **kwargs):
    return a <= c

funcs = [f1, f2, f3]

Now you can define a function that will pass the parameters. You'll need to define which parameters it intends to pass -- but it will always pass them all:

def func_caller(funcs):
    param_map = {
        'a': get_a_somehow(),
        'b': get_b_somehow(),
        'c': get_c_somehow(),
        ...
    }
    for func in funcs:
        if func(**param_map):
            print("Hello World!")

There are other way to make the "contract" between func_caller and the functions that it is calling even more binding (e.g. pass the params as a more structured object like a namedtuple).

from collections import namedtuple
FuncCallerParams = namedtuple('FuncCallerParams', 'a,b,c')

def f1(func_caller_params):
   return func_caller_params.a > func_caller_params.b
...

funcs = [f1, f2, ...]

def func_caller(funcs):
    a = ...
    b = ...
    c = ...
    fcp = FuncCallerParams(a, b, c)
    for func in funcs:
        if func(fcp):
           ...