2013-09-09 3 views
3

Итак, я создал функцию, которая применяет действие (в данном случае умножение точки массива с синусоидой, но это не имеет значения для моего вопроса), чтобы массив.Возвращает переменное имя извне функции, поскольку строка внутри функции python

Теперь я создал еще одну функцию, с помощью которой я хочу создать код python string, чтобы применить первую функцию несколько раз позже. Ввод второй функции может быть либо string, либо array, так что я могу использовать вторую функцию на своем собственном выходе, если это необходимо. Мой метод получения имени переменной в строке работает вне функции.

Вход:

var = np.array([[1,3],[2,4]]) # or sometimes var = 'a string' 

if type(var)==str: 
    var_name = var 
else: 
    var_name = [ k for k,v in locals().items() if v is var][0] 

var_name 

Выход:

'var' 

Так вот var переменные (либо массив или строка), подаваемый к функции, в данном случае массив. Оператор if прекрасно возвращает мне свое имя.

Однако, когда я использую это внутри своей функции, независимо от того, какой ввод я им даю, на самом деле он ищет var в locals(). Как-то это не принимает var от входа функции.

Определение:

def functionTWO(var, listoflistsofargs=None): 
    if type(var)==str: 
     var_name = var 
    else: 
     var_name = [ k for k,v in locals().items() if v is var][0] 
    if listoflistsofargs==None: 
     return var_name 
    command = [] 
    for i in range(len(listoflistsofargs)): 
     if i==0: 
      command.append('functionONE(') 
      command.append(var_name) 
      command.append(',%.17f, %.17f)' % tuple(listoflistsofargs[i])) 
     else: 
      command.insert(0,'functionONE(') 
      command.append(',%.17f, %.17f)' % tuple(listoflistsofargs[i])) 
    ''.join(command) 
    command[0] = var_name + ' + ' + command[0] 
    return ''.join(command) 

Вход:

somearray = np.array([[1,2,3],[1,2,3],[1,2,3]]) 
args = [[1,3],[6,5]] 
command = functionTWO(somearray, args) 
command 

Выход:

NameError: name 'var' is not defined 

Wanted выход:

'functionONE(functionONE(somearray, 1, 3), 6, 5)' 

Почему listoflistsofargs берется из входной функции и var нет? Я указываю var в списке непонимания в определении functionTWO. Обычно, когда я пользуюсь списками с функциями ввода, он работает нормально. Кто-нибудь знает, почему это не так? Заранее спасибо!

EDIT: Таким образом, я думаю, что ответ dont. Реализация классов Marcin выглядит намного чище и примерно того же порядка количества кода. Жаль, что я не мог заставить это работать внутри функции. Для других donts (на самом деле другие идеи) об использовании имен переменных в виде строк есть вопрос this, где я получил приведенное выше список имен переменных.

+0

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

+0

@sybren Ну, я хотел быть в состоянии выполнить ту же функцию произвольно количество раз на множестве. Мне было глупо, что я могу легко ввести его в консоль, но я не знал, как легко сделать функцию, поэтому я просто создал функцию типа. Угадайте, что есть «лучшие» способы. Я пытаюсь их изучить :) – Leo

ответ

4

Вы не можете передать переменную как строку *, и вы не должны этого делать.

Если вы хотите передать значение между функциями, обычный способ - передать его в качестве параметра и вывести его как возвращаемое значение.

Если это неудобно, обычным решением является объект: определите класс, который несет как общую переменную, так и методы, действующие на переменную.

Если вам нужно создать объекты команды, гораздо лучше сделать это структурированным способом. Например, если вы хотите передать функции и параметры, вы можете в буквальном смысле просто передать объект функции и параметры в кортеже:

def foo(): 
    return (functionONE,somearray,1,3) 

command = foo() 
command[0](*command[1:]) 

Если вы хотите встроить такие команды в команды, вы, вероятно, хотите обернуть это классом, чтобы вы могли рекурсивно оценивать параметры. На самом деле, вот немного оценщик:

def evaluator(object): 
    def __init__(self,func=None,params=None): 
     self.func = func 
     self.params = params 

    def eval(self,alternativeparams=None): 
     if alternativeparams is not None: 
      params = alternativeparams 
     else: 
      params = self.params 

     if params is not None: 
      evaluatedparams = (item() if callable(item) else item for item in params) 
     else: evaluatedparams = None 

     if func is not None: 
      return self.func(*(evaluatedparams or())) 
     else: return evaluatedparams 
    def __call__(self, *params): 
     return self.eval(params if params else None) 

Хотя есть хаки, с помощью которого вы можете передать ссылки на локальные переменные из функции, это не хорошая идея, потому что вы в конечном итоге создать свой собственный полусырой объектной системы, которую трудно понять.

* Это потому, что переменная имеет имя (которое представляет собой строку) и контекст, который отображает имена в строки. Итак, вам нужно, по крайней мере, передать кортеж, чтобы действительно передать переменную.

+0

не может быть более сильным термином, чем я бы использовал, но да +1 –

+0

@JoranBeasley достаточно справедливо, но, как показывает проблема ОП, на самом деле это не передача переменной, так как имя без контекста , – Marcin

+0

@Marcin Очень приятное объяснение, спасибо! Мне все еще кажется, что нет более быстрого способа сделать то, что я могу ввести в консоль очень быстро сам. Ваше решение более элегантно, чем мое (в конце концов я прибегал к тому, что для этой функции был зарезервирован глобальный ** var **). Чтобы иметь возможность использовать ваше решение, мне нужно будет изучить, какие классы и как они работают. Но я думаю, что это не будет в последний раз, когда они нуждаются в них.Так что спасибо за ваше решение и объяснение, почему мой метод не рекомендуется. – Leo

1

Причина, по которой вы получаете сообщение об ошибке NameError: name 'var' is not defined, когда вы завертываете все это в функцию: locals().items() относится к локально определенным переменным. на самом деле локально определенные переменные в ваших функциях - это только переменные, определенные внутри функции, и те, которые переданы в качестве аргументов функции.

Как следует из названия, locals().items() является локальным и будет состоять из разных переменных в зависимости от того, где он вызывается в вашем скрипте.

Наоборот, globals().items() состоит из всех глобальных переменных, поэтому попробуйте использовать его вместо этого в своих функциях, он должен сделать трюк.

Для получения дополнительной информации просмотрите глобальные и локальные переменные, а также область переменных в Python. Ответ

1

презентующего работает в Python 3

def get_variable_name(*variable): 
    return [ k for k,v in globals().items() if v is variable[0]][0] 

пример:

>> test = 'sample string' 
>> get_variable_name(test) 
'test' 
>> 

Единственная проблема в том, что это немного грязный.