1

I'm doing the following in the python interpreter and it works:

rhce=rhcsa=0
args=['rhce','rhcsa']
for cert in args:
    exec(cert+'+=1')
    print(eval(cert))

>>> 1
>>> 1

As you can see the variable is incremented, whether you use print(rhce) or print(eval(cert)). However, when I put the exact same snippet of code inside a class function, it no longer works. No exceptions are thrown, but the variable never increments. It's like the exec is not working:

def addCertUser(self,userid,args):
    rhcsa=rhce=0

    print(args)
    try:
        for cert in args:
            exec(cert+'+=1')
            print(eval(cert))
    except Exception as e:
        print(e)


>>> ['rhce', 'rhcsa']
>>> 0
>>> 0

What am i missing here?

musca999
  • 341
  • 2
  • 12
  • 1
    why do you need to use eval? why not just use a dict to map names to int values? – Chris Doyle Mar 19 '20 at 18:11
  • You're not showing how you call the function. It is necessary to provide a [mre] – Tomerikoo Mar 19 '20 at 18:22
  • 1. I don't know, why it doesn't work, but the way to make it work is to replace `rhcsa = rhce = 0` with `exec("rhcsa = rhce = 0")` 2. As @ChrisDoyle had mentioned, using eval and exec in production code is really a bad practice, you may want to use the following: https://pastebin.com/PTV5SAbd – Kolay.Ne Mar 19 '20 at 18:54

2 Answers2

0

The reason for getting a different result is that the scope of the variables you're trying to modify dynamically has changed between the 2 examples, from a module level scope to local function scope.

Using exec to modify local variables does not guarantee any outcome, as you may see in the documentation of the exec function and should be avoided.

See another detailed response here and here

Vitaliy
  • 291
  • 1
  • 14
0

Its never a good idea to eval or exec code, 99 times out of 100 there is a better way to do it. In this case unless you have any other reason that really needs to use eval and exec you could achieve what your trying with a dict. it can hold a key ("name") used to reference or look up your value quite safely.

class MyClass:
    def __init__(self):
        self.my_counts = {
            'rhce': 0,
            'rhcsa': 0
        }
    def add_cert_user(self, userid, args):
        print("start of function", self.my_counts)
        for cert in args:
            if cert  in self.my_counts:
                self.my_counts[cert] += 1
        print("end of function", self.my_counts)

me = MyClass()
args = ['rhce','rhcsa']
me.add_cert_user("test", args)
me.add_cert_user("test", args)
me.add_cert_user("test", args)

OUTPUT

start of function {'rhce': 0, 'rhcsa': 0}
end of function {'rhce': 1, 'rhcsa': 1}
start of function {'rhce': 1, 'rhcsa': 1}
end of function {'rhce': 2, 'rhcsa': 2}
start of function {'rhce': 2, 'rhcsa': 2}
end of function {'rhce': 3, 'rhcsa': 3}
Chris Doyle
  • 10,703
  • 2
  • 23
  • 42