Страницы

Поиск по вопросам

вторник, 20 ноября 2018 г.

Имя переменной, переданной в функцию

Можно ли как-то узнать имя переменной, которую передали в функцию:
def f(x): ...
y = 1 z = 2 f(y) # напеччатет y f(z) # напеччатет z


Ответ

Это можно сделать в CPython, но не рекомендуется -- в зависимости от вашей конкретной задачи, могут более удачные решения существовать, чем пытаться имя объекта из вызываемого окружения определить:
>>> import inspect >>> def f(x): ... caller_locals = inspect.currentframe().f_back.f_locals ... print(*[name for name, value in caller_locals.items() if x is value]) >>> y = 1 >>> z = 2 >>> f(y) y >>> f(z) z

В зависимости от того как REPL реализована, можно различить f(y) от f(z) вызовы, даже если y = z = 1
>>> import dis >>> import inspect >>> def f(x): ... caller_frame = inspect.currentframe().f_back ... dis.dis(caller_frame.f_code) ... >>> y = z = 1 >>> f(y) 1 0 LOAD_NAME 0 (f) 2 LOAD_NAME 1 (y) 4 CALL_FUNCTION 1 6 PRINT_EXPR 8 LOAD_CONST 0 (None) 10 RETURN_VALUE >>> f(z) 1 0 LOAD_NAME 0 (f) 2 LOAD_NAME 1 (z) 4 CALL_FUNCTION 1 6 PRINT_EXPR 8 LOAD_CONST 0 (None) 10 RETURN_VALUE >>> f(1) 1 0 LOAD_NAME 0 (f) 2 LOAD_CONST 0 (1) 4 CALL_FUNCTION 1 6 PRINT_EXPR 8 LOAD_CONST 1 (None) 10 RETURN_VALUE
Имя переданной переменной присутствует в байт-коде вызывающего frame. Программно можно найти вызов функции (CALL_FUNCTION инструкция) и посмотреть какое именно имя передано (если вообще имя было использовано) из caller_frame.f_code.co_names списка. К примеру в CPython 2:
>>> import inspect >>> import byteplay # $ pip install byteplay >>> def f(x): ... bc = byteplay.Code.from_code(inspect.currentframe().f_back.f_code) ... i = next(i for i, (opcode, _) in enumerate(bc.code) if opcode == byteplay.CALL_FUNCTION) ... print bc.code[i-1][1] ... >>> y = z = 1 >>> f(y) y >>> f(z) z >>> f(1) 1
Disclaimer: ответ для образовательных целей, не для использования в рабочем коде.

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

Отправить комментарий