диктонар локальных () в Python только для чтения при отладке? - PullRequest
0 голосов
/ 24 февраля 2012

Я использую замечательный sympy в python, чтобы сгенерировать расширенную систему системы ODE для вычисления прямой чувствительности состояний по отношению к состояниям.Моя цель - оптимизировать систему ODE.Если бы у меня была система x1 ... x10 и параметры a1 ... a5, то расширенная система имела бы 10 + 10 * 5 состояний.Приведенный мной код sympy генерирует дополнительные состояния и присваивает их переменным x1 ... x60.

Позже я использую интеграцию в numpy для решения расширенной системы.Поэтому я должен написать функцию, которая возвращает rhs () ODE-системы - что-то вроде этот код (если кто-то из вас работает с numpy, пожалуйста, исправьте ошибку в two_springs.py, строка 29 - m2 отсутствует ).

И моя проблема: я хочу, чтобы внутри функции назначались переменные x1 ... x_end динамически (общее количество состояний будет меняться в зависимости отсколько параметров я использую для чувствительности).Я был в восторге, тогда я нашел встроенную функцию locals () в Python.С этот пост Я думал, что это должно работать:

def test_l(w, t):
for ii in range(len(w)):
    varStr="a%d" % (ii)
    locals()[varStr]=w[ii]
return a1*t+a0
w0 = [1.0, 1.0]
t0 = 1.0
f_x=test_l(w0, t0)
print "func res-> %1.4f\n" % (f_x)

Запуск сценария, который я получаю глобальное имя 'a1' не определено .Позже я узнал, что localst () на самом деле только для чтения .Меня смущает то, что если я отлаживаю функцию с pde на в ipython , то переменные a1 и a0 действительно существуют внутрифункция ... Запуск кода с помощью 'pdb on' Я все еще получаю сообщение об ошибке, выполнение программы останавливается на return () , но a1 и a0 фактически существуют в рабочем пространстве функции.

ipdb> a1 1.0

ipdb> a0 1.0

Как получается, что localals () доступен только для чтения, но при отладке с помощью pdb словарь может быть фактически изменен?

PS: я решил свою проблему следующим образом:

 for ii in range(len(w)):
    #varStr="a%d" % (ii)
    #locals()[varStr]=w[ii]
    varStr="a%d=w[%d]" % (ii, ii)
    exec(varStr)
 return a1*t+a0

Ответы [ 2 ]

4 голосов
/ 24 февраля 2012

Позвольте мне начать с отказа от того, что я ничего не знаю о симпати.Я только взглянул на документы в ответ на ваш комментарий о том, что вы не можете создавать символы из словаря ...

locals(), как вы предположили, только для чтения.Цитирование из документации по python:

Примечание. Содержимое этого словаря не должно изменяться;изменения могут не влиять на значения локальных и свободных переменных, используемых интерпретатором.

Я понимаю, что изменение его при любых обстоятельствах было бы непредсказуемым.Таким образом, если переменные активны во время отладки, я предполагаю, что в этих обстоятельствах существует различие в сборке мусора.Или ... непредсказуемость.

Что касается символических переменных в sympy.Они просто кажутся стандартным классом Python.Разве это не сработало бы для создания объектов Symbol из текста, созданного вами динамически?

from sympy import *
myVars = {'a1':1.0, 'a2':1.0 }
print [Symbol(k) for k in myVars.iterkeys()]
# [a₁, a₂]

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

3 голосов
/ 24 февраля 2012

Причина предупреждения в документации Python о записи в locals(), о котором упоминает jdi, заключается в том, что большую часть времени вещи, которые вы изменяете в locals(), не распространяются обратно на фактические локальные переменные.Это потому, что местные жители могут приехать из более чем одного места.Причина, по которой locals() является в первую очередь функцией, а не словарем, заключается в том, что может существовать некоторый код, который собирает все локальные переменные из мест их существования в одно место, где их удобно читать.

Бывают случаи, когда запись в словарь, возвращаемый locals(), работает.Если вы включите оператор exec в любое место вашей функции, даже если он никогда не выполняется (т.е. после оператора return), запись в locals() будет работать.Однако локальные переменные будут тогда на медленнее , чем в противном случае, потому что Python не может использовать «быстрые» коды операций для доступа к локальным переменным по индексу, когда он не знает во время «компиляции» имена всех локальных переменных.переменные.

def foo(val):    # circuitously returns value passed in
    locals["b"] = val
    return b
    exec ""

Кроме того, вы обнаружите, что замыкания (разделение переменных между внутренней и внешней функцией) не работают.

def foo(a):   # can't define this function
    def bar():
       return a
    return bar
    exec ""

Я считаю, что интерпретатор Pythonтакже делает некоторую дополнительную магию с locals(), пока активна функция трассировки.

Это все специфично для CPython;Jython и IronPython, вероятно, ведут себя по-разному.

...