команда python exec работает в консоли, но не в программе

#python #python-3.x

#python #python-3.x

Вопрос:

Проблема в том, что запуск exec() для переменной с именем именованного аргумента не работает при нормальной работе программы, но установка точки останова и выполнение рассматриваемой строки кода в том же месте, похоже, работают.

Воспроизведение проблемы следует:

 """

    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()
 

Этот минимально воспроизводимый пример покажет, что запуск программы приведет к выводу содержимого parameter_a и parameter_b (в этом проблема). Желаемым результатом будет parameter_a, а parameter_b будет пустым списком. Если вы поставили точку останова в exec('self = self._replace({0}=[])'.format(field)) строке и во время отладки откройте консоль python в pycharm и запустите эту строку кода « exec('self = self._replace({0}=[])'.format(field)) » в консоли. она очистит параметры_a и paramter_b (давая желаемый результат).

Комментарии:

1. вы не можете изменять локальные переменные с exec помощью / eval . Вы не должны использовать exec здесь в первую очередь

2. Но очевидно, что это не совсем тот случай, если я могу использовать exec для изменения локальных переменных в консоли python. И я согласен, что в этом случае лучше не использовать exec / eval.

3. Нет, вы не можете, в Python 3. Консоль отладчика отличается от обычной среды (на самом деле она уже используется exec …)

4. Спасибо, я этого не знал.

Ответ №1:

Вам это не нужно exec : если вам нужен аргумент ключевого слова с динамическим именем, используйте **kwargs синтаксис. Вы также можете заменить все поля одновременно, вместо того, чтобы вызывать _replace несколько раз в цикле:

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

Комментарии:

1. Я забыл ** , когда я впервые устал kwargs проходить. Это решается для желаемого результата / результата. Спасибо. Прежде чем я отмечу это как ответ, знаете ли вы, почему exec ведет себя так странно, что не работает в этой программе?

2. @Theisen вы читали документацию для exec ? она предупреждает вас, что изменения локальных переменных не будут работать.

3. Это не странное поведение — это ожидаемое поведение. exec не изменяет значения локальных переменных, таких как self . Как советуют документы для exec функции: «Передайте явный словарь locals, если вам нужно увидеть влияние кода на locals после возврата функции exec()».