是否可以在Python中获取传递参数的名称?
具体来说,我希望能够做到这一点:
def a(name):
print "the actual passed parameter is %s" %(???)
它解决了什么?
因此,如果我需要在袋子和篮子中分发硬币,比如bag_list和basket_list,我不需要发送明确的标识符'bag'或'basket'
我目前正在解决这个问题。我目前正在为此目的使用(全球)字典 -
ID = {'bag': bag_list, 'basket': basket_list}
def a(name, id):
dist_list = ID[id]
它还归结为将变量名称转换为字符串,因为所需的行为也可以建模为:
def a(name):
name = ???get variable name as string magically???
if name.startswith('bag'):
dist_list = ID['bag']
else:
dist_list = ID['basket']
https://stackoverflow.com/a/9121991/1397945已全面回答了重新建模的问题,但我正在重新发布
感谢。
答案 0 :(得分:3)
这是可能的 - 但我认为这是一个肮脏的黑客。在阅读我的解决方案之后,如果你真的想这样做,你应该退后一步思考。
def a(name):
global_variables = globals()
try:
name_of_passed_in_variable = [x for x in global_variables if id(global_variables[x]) == id(name)][0]
except Exception:
name_of_passed_in_variable = "unknown"
print name_of_passed_in_variable, name
my_name = "Tom"
a(my_name)
a("Mike")
second_name = my_name
a(second_name)
会给出输出:
my_name Tom
unknown Mike
my_name Tom
通过我的示例,您还可以看到这种方法的缺点。
对于后一个问题,你当然可以实现一些逻辑来应对它 - 或者这对你来说根本不是问题。
答案 1 :(得分:2)
我认为你遇到的问题是争论的不同。有一些关键字参数,其中名称由调用者和简单的位置参数明确说明。你可以这样做,
def a(**kwargs):
if 'bag' in kwargs:
dist_list = ID['bag']
else:
dist_list = ID['basket']
你必须传递像这样的变量,
a(bag=...)
或者如果您想查看参数startswith
包或篮子是否可以,
def a(**kwargs):
if any(k.startswith('bag') for k in kwargs.iterkeys()):
dist_list = ID['bag']
elif any(k.startswith('basket') for k in kwargs.iterkeys()):
dist_list = ID['basket']
else:
raise Exception('a requires argument starting with `basket` or `bag`')
但是你有问题确定哪个钥匙从包或篮子开始,所以我可能会这样做,
def a(**kwargs):
valid_key = [k for k in kwargs.iterkeys() if k.startswith('bag') or k.startswith('basket')][0]
if valid.key.startswith('bag'):
dist_list = ID['bag']
elif valid.key.startswith('basket'):
dist_list = ID['basket']
else:
raise Exception('a requires argument starting with `basket` or `bag`')
答案 2 :(得分:1)
这样的事情会适合你的用例吗?
>>> class Inventory(object):
basket = 0
bag = 0
def add_coins(self, **kwargs):
if 'bag' in kwargs:
self.bag += kwargs['bag']
if 'basket' in kwargs:
self.basket += kwargs['basket']
>>> i = Inventory()
>>> i.add_coins(bag=6)
>>> i.bag
6
>>> i.add_coins(bag=2)
>>> i.bag
8
>>> i.basket
0
答案 3 :(得分:1)
通常,你想要的是不可能的,因为Python不会传递附加了名字的对象。
在调用函数的情况下,您可以获取具有名称/值对的字典,如果,则用户始终使用关键字参数调用该函数。
所以你可以这样做:
def a(**kwargs):
if len(kwargs) != 1:
raise ValueError("only pass a single keyword arg starting with 'bag' or 'basket'")
# Above line is Python 3.x syntax; below line is Python 2.x syntax
# raise ValueError, "only pass a single keyword arg starting with 'bag' or 'basket'"
name, value = list(kwargs.items())[0]
if name.startswith('bag'):
dist_list = ID['bag']
else:
dist_list = ID['basket']
# I don't know what you want next, but let's say you want to append:
dist_list.append(value)
然后用户必须像这样调用函数:
a(bag=3)
a(basket=5)
编辑:Python 3.x的代码现在正确,可以很容易地修改为Python 2.x(参见注释)。
编辑:现在我考虑一下,我们可以概括一下。我要将ID
重命名为_containers
。
def a(**kwargs):
for key, value in kwargs.items():
if key in _containers:
_containers[key].append(value)
else:
raise ValueError("invalid container name '%s'" % key)
现在,您可以通过一次调用附加多个容器。但它有点棘手,因为用户可能会这样做:
a(bag=1, basket=2, bag=3)
bag=1
永远不会发生,因为bag
将在字典中设置为3
。 (可能有一种棘手的方法用一个带有重载函数的自定义类替换字典,但这种方式很疯狂......我不推荐那些棘手的代码。)
它不是那么好,但是如果你想要开始 bag
或其他什么工作,那就可以了:
def a(**kwargs):
for key, value in kwargs.items():
found = False
for container_name in _containers:
if key.startswith(container_name):
_containers[container_name].append(value)
found = True
break
if not found:
raise ValueError("no container name matched '%s'" % key)