Theisen
Theisen

Reputation: 53

python exec command works in console but not in program

The problem is that running exec() on a variable with the name of a named argument does not work in normal operation of the program, but setting a break point and executing the line of code in question at the same location seems to work.

Reproduction of the issue follows:

"""

    LEGACY CODE, CANNOT CHANGE
    vvvvvvvvvvv

"""

from collections import namedtuple


class A_Object(namedtuple('A_object', 'parameter_a' ' parameter_b')):

    def __new__(cls, *args, **kwargs):
        init = super(A_Object, cls).__new__(cls, parameter_a=[], parameter_b=[])
        return init

    """
    
        ^^^^^^^^^^^
        LEGACY CODE, CANNOT CHANGE
    
    """

    def _remove_all_data(self):
        for field in self._fields:
            print("removing field:", field)

            # This does not work in the normal execution of the program,
            # but if you set a break point and execute the same command in the python console ( in Pycharm ) it works.
            exec('self = self._replace({0}=[])'.format(field))

        return self


def driver():
    a = A_Object()

    a.parameter_a.append('a')
    a.parameter_a.append('b')
    a.parameter_a.append('c')

    a.parameter_b.append(1)
    a.parameter_b.append(2)
    a.parameter_b.append(3)

    # Try to remove all data from properties.
    a = a._remove_all_data()

    tmp = a._asdict()

    for k in tmp.keys():
        for i in range(0, len(tmp[k])):
            print('{}[{}]='.format(k,i), tmp[k][i])


if __name__ == '__main__':
    driver()

This minimum reproducible example will show that running the program will output the contents of parameter_a, and parameter_b ( That is the issue ). The desired outcome would be parameter_a, and parameter_b to be empty list. If you put a break point on the exec('self = self._replace({0}=[])'.format(field)) line and during debug open up the python console in pycharm and run that line of code "exec('self = self._replace({0}=[])'.format(field))" in the console. it will clear the parameter_a, and paramter_b ( giving the desired output ).

Upvotes: 0

Views: 433

Answers (1)

kaya3
kaya3

Reputation: 51152

You don't need exec for this: if you want a dynamically-named keyword argument, use the **kwargs syntax. You might as well also replace all the fields at once instead of calling _replace multiple times in a loop:

def _remove_all_data(self):
    return self._replace(**{ f: [] for f in self._fields })

Upvotes: 2

Related Questions