Reputation: 53
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
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