Есть ли способ получить имена переданных аргументов функции в python?
Мне нравится знать, что такое имена локальных переменных, когда они передаются функции. Я не уверен, что это вообще возможно. Рассмотрим этот пример:
определение функции:
def show(x):
print(x)
использование:
a = 10
show(a)
это печатает 10. Но мне нравится печатать "a = 10". Возможно ли это в python?
Ответы
Ответ 1
Нет, вы не можете знать, какое имя принадлежит локальной переменной, используемой для передачи значения вашей функции.
В любом случае это невозможно. Каким будет имя переменной в следующем примере?
arguments = ('a', 1, 10)
somefunction(*(arguments[:2] + [10]))
Здесь мы передаем 3 аргумента, два взяты из кортежа, который мы определили ранее, и одно буквальное значение, а все три переданы с использованием синтаксиса списка аргументов переменных.
Ответ 2
Не совсем так. Однако вы можете добиться чего-то подобного:
def show(**kwargs):
print(', '.join('%s=%s' % kv for kv in kwargs.items()))
show(a=20)
Ответ 3
Мне нравится ответ на этот вопрос, который содержится в FAQ по программированию на Python, цитируя Фредрика Лунда:
Точно так же, как вы получите имя этой кошки, которую вы нашли на крыльце: сам кот (объект) не может сказать вам его имени, и он действительно не волнует - так единственный способ узнать, что его называют спросить всех своих соседей (пространства имен), если их кошка (объект)...
.... и не удивляйтесь, если вы обнаружите, что его знают многие имена или вообще не имеют имени!
Ответ 4
Я предупреждаю, что следующее решение получит несколько критических замечаний
def show(*x):
for el in x:
fl = None
for gname,gobj in globals().iteritems():
if el==gobj:
print '%s == %r' % (gname,el)
fl = True
if not fl:
print 'There is no identifier assigned to %r in the global namespace' % el
un = 1
y = 'a'
a = 12
b = c = 45
arguments = ('a', 1, 10)
lolo = [45,'a',a,'heat']
print '============================================'
show(12)
show(a)
print '============================================'
show(45)
print
show(b)
print '============================================'
show(arguments)
print
show(('a', 1, 10))
print '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
show(*arguments)
print '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
show(*(arguments[1:3] + (b,)))
результат
============================================
a == 12
a == 12
============================================
c == 45
b == 45
c == 45
b == 45
============================================
arguments == ('a', 1, 10)
arguments == ('a', 1, 10)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
y == 'a'
un == 1
There is no identifier assigned to 10 in the global namespace
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
un == 1
There is no identifier assigned to 10 in the global namespace
c == 45
b == 45
Ответ 5
Кажется, что это невозможно в Python, но на самом деле это возможно в С++.
#define show(x) std::cout << #x << " = " << x << std::endl
Ответ 6
Новое решение Использование readline
Если вы находитесь в интерактивном сеансе, здесь крайне наивное решение, которое обычно работает:
def show(x):
from readline import get_current_history_length, get_history_item
print(get_history_item(get_current_history_length()).strip()[5:-1] + ' = ' + str(x))
Все, что он делает, это прочитать последний ввод строки в буфере интерактивного сеанса, удалить все ведущие или завершающие пробелы, а затем дать вам все, кроме первых пяти символов (надеюсь, show(
) и последнего символа (надеюсь, )
)), таким образом оставляя вас с тем, что было передано.
Пример:
>>> a = 10
>>> show(a)
a = 10
>>> b = 10
>>> show(b)
b = 10
>>> show(10)
10 = 10
>>> show([10]*10)
[10]*10 = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
>>> show('Hello' + 'World'.rjust(10))
'Hello' + 'World'.rjust(10) = Hello World
Если вы используете OS X, используя версию Python, которая поставляется вместе с ней, у вас нет readline
по умолчанию, но вы можете установить его через pip
. Если вы находитесь в Windows, readline
для вас не существует... вы могли бы использовать pyreadline
из pip
, но я никогда не пробовал его, поэтому не могу сказать, является ли это приемлемым заменителем или нет.
Я оставляю этот код более пуленепробиваемым как упражнение для читателя. Следует рассмотреть, как заставить его обрабатывать такие вещи:
show(show(show(10)))
show(
10
)
Если вы хотите, чтобы такие вещи отображали имена переменных из script, вы можете изучить использование и получение исходного кода вызывающего фрейма. Но учитывая, что я не могу придумать, почему вы когда-либо хотели бы использовать show()
в script или почему вы усложнили бы эту функцию, просто для того, чтобы обращаться с людьми, намеренно привинчивающимися к ней, как я сделал выше, я не собираюсь тратить мое время прямо сейчас выясняет это.
Исходное решение с использованием inspect
Здесь мое оригинальное решение, которое сложнее и имеет более вопиющий набор предостережений, но более переносимо, поскольку оно использует только inspect
, а не readline
, поэтому работает на всех платформах и находится ли вы в интерактивный сеанс или в script:
def show(x):
from inspect import currentframe
# Using inspect, figure out what the calling environment looked like by merging
# what was available from builtin, globals, and locals.
# Do it in this order to emulate shadowing variables
# (locals shadow globals shadow builtins).
callingFrame = currentframe().f_back
callingEnv = callingFrame.f_builtins.copy()
callingEnv.update(callingFrame.f_globals)
callingEnv.update(callingFrame.f_locals)
# Get the variables in the calling environment equal to what was passed in.
possibleRoots = [item[0] for item in callingEnv.items() if item[1] == x]
# If there are none, whatever you were given was more than just an identifier.
if not possibleRoots:
root = '<unnamed>'
else:
# If there is exactly one identifier equal to it,
# that probably the one you want.
# This assumption could be wrong - you may have been given
# something more than just an identifier.
if len(possibleRoots) == 1:
root = str(possibleRoots[0])
else:
# More than one possibility? List them all.
# Again, though, it could actually be unnamed.
root = '<'
for possibleRoot in possibleRoots[:-1]:
root += str(possibleRoot) + ', '
root += 'or ' + str(possibleRoots[-1]) + '>'
print(root + ' = ' + str(x))
Здесь случай, когда он работает отлично (один из вопроса):
>>> a = 10
>>> show(a)
a = 10
Вот еще один забавный случай:
>>> show(quit)
quit = Use quit() or Ctrl-Z plus Return to exit
Теперь вы знаете, как эта функциональность была реализована в интерпретаторе Python - quit
является встроенным идентификатором для str
, в котором говорится, как правильно выйти.
Здесь несколько случаев, когда это меньше, чем вы могли бы хотеть, но... приемлемо?
>>> b = 10
>>> show(b)
<a, or b> = 10
>>> show(11)
<unnamed> = 11
>>> show([a])
<unnamed> = [10]
И вот случай, когда он печатает истинное утверждение, но определенно не то, что вы искали:
>>> show(10)
<a, or b> = 10