-1

This code does not work properly:

def anyFunction(var):
  for i in range(3):
    try:
      exec(var+"+=1")
    except NameError:
      exec("global "+var+"\n"+var+"=1"
  return var

anyFunction("varInput")
print(varInput)

varInput should be 3, but is 1. For the code to work, you need to add a global like this :

def anyFunction(var):
  for i in range(3):
    try:
      exec("global "+var+"\n"+var+"+=1")
    except NameError:
      exec("global "+var+"\n"+var+"=1"
  return var

anyFunction("varInput")
print(varInput)

Does anyone know if this is a Python bug or is intended ?

4
  • 1
    when you use exec(var+"+=1") in the try block, Python is executing this code in the function's local scope, but without a global declaration Commented May 21 at 11:09
  • 2
    Please never write code like that for purposes other than learning (and even for learning this is very much questionable). Commented May 21 at 11:09
  • This is explained in the fine manual, specifically "In all cases, if the optional parts are omitted, the code is executed in the current scope". Commented May 21 at 11:09
  • In Python, you only operate on values, not variables. You can increment the value referenced by a variable, but you shouldn't try to modify the variable itself, especially not indirectly using a string containing its name. Commented May 21 at 16:18

1 Answer 1

2

Why this is bad practice?
When you pass user-provided input directly to exec(), you are essentially allowing arbitrary code execution.

Like;

funcany("varInput; __import__('os').system('rm -rf /')")

The executed code runs with the same privileges as your application - code injection

Coming to your issue:
When you use exec() inside a function, the executed code operates in the function's local namespace by default.

In python:

a variable that gets assigned a value within a function is treated as local to that function unless explicitly declared global

def anyFunction(var):
  for i in range(3):
    try:
      exec(var+"+=1") 
    except NameError:
      exec("global "+var+"\n"+var+"=1")  
  1. First iteration - The variable doesn exist -> exception -> creates global variable with value 1

  2. Second iteration - Tries to increment a local variable (not the global one) -> fails silently

  3. Third iteration -> same issue as second

Instead you use a dictionary to manage your variables

def safe_increment(var_name, count=3, state=None):
   if state is None:
       state = {}
   
   if var_name not in state:
       state[var_name] = 0
       
   for _ in range(count):
       state[var_name] += 1
       
   return state[var_name], state

var_state = {}
final_value, var_state = safe_increment("varInput", state=var_state)
print(f"varInput = {final_value}")
print(f"State: {var_state}")

Dynamic code execution via exec() and eval() should be avoided whenever possible especially with user input as it's one of the most severe security vulnerabilities in python applications.

Sign up to request clarification or add additional context in comments.

1 Comment

I actually don't use this code, I have some conditions before, I found no other way to make my programm work (it's a python compiler for a minimalist language)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.