简体   繁体   中英

Why am I getting a TypeError: 'str' object is not callable when using eval() on string that is python code

I have the following code which manipulates a function in the form of string and adds a timer to while loops to see if they take 2 seconds without returning. If so it returns 'error, infinite loop.'

Right now when I run this code it gives me a "TypeError: 'str' object is not callable".

def nico():
    otherTimer = '\n    current_time = time.time()\n    elapsed_time = current_time - start_time\n    print(elapsed_time)\n    if elapsed_time > 2:\n      return "error, infinite loop"'

    sample = '''def sample():\n  a = 1\n  while a == 1:\n    print("breh")
            '''


    for k in range(len(sample)): # insert srart time at top of function
        if sample[k] == ":":
            sample = sample[:k + 1] + "\n  start_time = time.time()\n" + sample[k+1:]
            break
    

    
    if "while" in sample: #insert timer in the while loop
        for i in range(len(sample)):
            if sample[i] + sample[i + 1] + sample[i + 2] + sample[i + 3] + sample[i + 4] == 'while':
                newstring = sample[i:]
    
                for j in range(len(newstring)):
                    if newstring[j] == ':':
                        print(sample[:i] + sample[i:] + otherTimer)
                        output = sample[:i] + sample[i:] + otherTimer
                        exec(output)

                        return eval('sample()')

I'm confused because this piece of code does what I want it to do, and the only difference is that I am storing the string function as the actual string instead of a variable in my exec() statement:

def delly():
    exec('def sample():\n  start_time = time.time()\n\n  a = 1\n  while a == 1:\n    print("breh")\n            \n    current_time = time.time()\n    elapsed_time = current_time - start_time\n    print(elapsed_time)\n    if elapsed_time > 2:\n      return "error, infinite loop"')
    return eval('sample()')

The sample variable is shadowing the sample function. There are no distinct namespaces in Python as everything is considered an object. So, when exec is called to define the function, it gets immediately hidden by the existing sample string. As such, calling eval will attempt to run the string variable as a function, returning the seen TypeError .

For an example:

# Defines a function named sample
def sample():
    print("Hello world!")

# Set a local variable with the same name and execute the global function
def test():
    sample = "some string"
    sample()

# Will throw a TypeError since the sample string shadows the function
test()

Wrapping the sample function in a string to exec and eval will return the same result:

def test():
    # Set a local variable named 'sample'
    sample = "some string"
    
    # Create a global function named 'sample'
    exec("def sample():\n    print('Hello world!')")

    # Throws TypeError as global function is shadowed by local variable
    eval('sample()')

test()

So, the solution? All you need to do is change the name of either the function or the local variable.

For further reading on this issue, I would suggest this explanation for understanding and the comment beneath on a good mindset to deal with this issue in the future.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM