1

I want to check an arbitrary (defined in data) set of rules expressed in text and eval() does the job nicely.

e.g. to define a rule to check that A and B are both valid:

Rule = "A and B"
print eval(Rule)

So how do I dynamically assign values to an arbitrary set of items?

I have a list of named Options and a list of Selections. Everthing in the Selections is considered valid (True) and everything in the Options, but not in the Selections is considered invalid (False).

So this code works but I don't like it because I am setting values within the local name space and I can't prevent an option name clashing with my local variables.

def CheckConstraints(self, Selections):
    'Validate the stored constraints'
    Good = True
    ## Undefined options default to False
    for i in self.Options:
        exec(i+" = False")  ## Bad - can I use setattr?
    ## Set defined Options to True
    for i in Selections:
        exec(i+" = True")  ## Bad - can I use setattr?
    for i in self.Constraints:
        if not eval( i ):
            Good = False
            print "Constraint Check Failure:", i, Selections
        else:
            print "Constraint Check OK:", i, Selections
    return Good

I have tried to use setattr, but it is not clear what setattr is setting and eval doesn't seem to be able to use the values set.

I'm on python 2.7x

Any suggestion welcome?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
paaste
  • 13
  • 2

1 Answers1

1

eval can take a dictionary as its second argument which contains a new environment. Create a dictionary env and set your new variables within there, which ensures it won't clash with your local namespace:

def CheckConstraints(self, Selections):
    'Validate the stored constraints'
    Good = True
    env = {}
    ## Undefined options default to False
    for i in self.Options:
        env[i] = False
    ## Set defined Options to True
    for i in Selections:
        env[i] = True
    for i in self.Constraints:
        if not eval(i, env):
            Good = False
            print "Constraint Check Failure:", i, Selections
        else:
            print "Constraint Check OK:", i, Selections
    return Good
David Robinson
  • 77,383
  • 16
  • 167
  • 187
  • I don't think this will handle the OP's case, though. As I understand it, we're trying to test whether rules contained in strings like `"A and B"` hold. – DSM Jan 20 '13 at 15:22
  • @DSM: That's true for the use of `eval` (now changed, thanks) but the use of `exec` is still unnecessary – David Robinson Jan 20 '13 at 15:23
  • @DSM: Actually, on second thought I don't think that's true here. If `i` contained the string `A and B` then the OP's line `exec(i+" = False")` would never work – David Robinson Jan 20 '13 at 15:25
  • But now the constraints have to be specified in the format `"self.Options['A'] and self.Options['B']"`, don't they? Otherwise the `eval` won't work. – DSM Jan 20 '13 at 15:26
  • @DSM: Ah, now I see- `Constraints` has a different set of values than `Options` or `Selections`. I'm deleting my answer until we get clarification from the OP – David Robinson Jan 20 '13 at 15:27
  • @DSM: I think I fixed the issue by creating a new dictionary for `eval` to use as its environment; see above – David Robinson Jan 20 '13 at 15:33
  • Thank you, yes passing the environment to eval is what I need. – paaste Jan 20 '13 at 15:44