Можно ли как-то узнать имя переменной, которую передали в функцию:
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: ответ для образовательных целей, не для использования в рабочем коде.
Комментариев нет:
Отправить комментарий