是否可以编写一个函数f
来获取混合数据的任意元组:
T = 1.0
N = 20
L = 10
args = (T,N,L)
f(*args) # or maybe f(T,N,L)?
并返回输出:
{'T':1.0, 'N':20, 'L':10}
有related question使用local
,但是一旦传递给函数,我似乎丢失了名字。有办法防止这种情况吗?我猜测变量是按值传递的,因此它们被认为是新对象。
答案 0 :(得分:3)
不,一般情况下*args
无法做到这一点。您必须使用关键字参数:
>>> def f(**kwargs):
... return kwargs
...
>>> f(T=1.0, N=20, L=10)
{'T': 1.0, 'L': 10, 'N': 20}
原因是*args
没有为个别参数引入名称;它只为它们的整个列表引入名称args
。该函数没有深入了解参数在其之外的名称(如果有的话)。
当参数数量固定时,您可以使用locals
执行此操作:
>>> def g(T, N, L):
... return locals()
...
>>> g(T=1.0, N=20, L=10)
{'L': 10, 'T': 1.0, 'N': 20}
(或明确地使用return {'T': T, 'N': N, 'L': L}
。)
答案 1 :(得分:2)
在Python中,变量只是附加到值的标签。因此,在调用函数时,无法从另一个范围知道您使用的标签。
答案 2 :(得分:2)
不幸的是,您的猜测是错误的,事实上整个问题都表明了对Python名称如何运作的误解。
Python对象总体上不知道他们的名字。如果您认为可以轻松指定a=b
,现在a
和b
都指向完全相同的对象,那么这是完全可以理解的。 Python的“变量”只是指向对象的名称,它们不以任何实际方式包含这些对象。将参数传递给函数时,您传递的是基础对象,而不是名称。接收函数只是将它们绑定到函数签名中指定的名称 - 或者,在您的情况下,只需将它们保存在args
中,而不给它们任何名称。
因此,当您询问如何获取对象在不同范围内的名称时,您无法询问对象本身。可能有一种方法可以做到这一点,但它涉及检查调用框架,我非常怀疑你想要。
答案 3 :(得分:1)
使用globals()
的解决方案。这仅在值在模块范围内是唯一的时才有效,因此它很脆弱 - 如果有重复项,它将选择指向该值的第一个名称,随意。是的,无论如何你最好不要这样做,而是重新思考问题。
def f(*names):
r = {}
for n in names:
r[[ name for name in globals() if globals()[name] is n ][0]] = n
return r
T = 1.0
N = 20
L = 10
print f(T,N,L)
{'T': 1.0, 'L': 10, 'N': 20}
答案 4 :(得分:0)
是的,据我所知,args是一个列表。要保留标签名称,您需要将dict传递给** kwargs,并使用local
显式或以编程方式设置名称。
您可以执行以下操作:
def filter_locals(caller_locals, *args):
filtered = {}
for key in args:
filtered[key] = caller_locals[key]
return filtered
然后:
X = 1
Y = 2
func(filter_locals(locals(), 'X', 'Y')
func将任意长度列表处理为kwargs。
答案 5 :(得分:0)
有必要将键和值作为单独的参数传递:
keys = ('T', 'N', 'L')
values = (1.0, 20, 10)
d = dict(zip(keys, values))
在您的代码中,行args = (T,N,L)
的计算结果为args = (1.0, 20, 10)
,变量T,N,L的“名称”将替换为其值。