Actual name of the passed parameter
是否可以在python中获取传递参数的名称?
具体来说,我希望能够做到:
1 2 | def a(name): print"the actual passed parameter is %s" %(???) |
它能解决什么问题?
所以,如果我需要把硬币放在袋子和篮子里,比如说"袋子清单"和"篮子清单",我不需要发送一个明确的标识符,上面写着"袋子"或"篮子"。
这就是我目前的工作方式。我目前正在使用(全球)字典-
1 2 3 4 | ID = {'bag': bag_list, 'basket': basket_list} def a(name, id): dist_list = ID[id] |
号
它还可以归结为将变量名转换为字符串,因为所需的行为也可以建模为:
1 2 3 4 5 6 | 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中得到了全面的回答,但我正在发布此消息
- 以防万一发生了一些修改&;
- 在Perl或Tcl等其他脚本语言中是否可以这样做。
- 更重要的是,如果两种建模方法不同,或者可以采用任何不同的方法。
谢谢。
这是可能的-但我认为这是一个肮脏的黑客。在阅读了我的解决方案之后,如果你真的想这样做,你应该后退一步,三思而后行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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) |
。
将给出输出:
1 2 3 | my_name Tom unknown Mike my_name Tom |
号
通过我的示例,您还可以看到这种方法的缺点。
- 如果在不分配变量的情况下直接传递字符串,则无法确定名称
- 如果对同一个变量有多个引用,则永远不会知道将使用哪个名称。
对于后一个问题,您当然可以实现一些逻辑来处理它——或者这对您来说完全没有问题。
我认为你的问题在于论点的不同。有关键字参数,其中名称由调用方显式声明,以及简单的位置参数。你可以这样做,
1 2 3 4 5 | def a(**kwargs): if 'bag' in kwargs: dist_list = ID['bag'] else: dist_list = ID['basket'] |
。
你必须传递这样的变量,
1 | a(bag=...) |
或者,如果您想查看参数
1 2 3 4 5 6 7 | 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`') |
。
但是你有一个问题,那就是决定哪把钥匙从袋子或篮子开始,所以我可能会这样做,
1 2 3 4 5 6 7 8 | 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`') |
一般来说,您想要的是不可能的,因为Python不传递附加名称的对象。
在调用函数的情况下,如果用户总是使用关键字参数调用函数,则可以获取具有名称/值对的字典。
所以你可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 | 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) |
号
然后用户必须这样调用函数:
1 2 | a(bag=3) a(basket=5) |
编辑:代码现在对于python 3.x是正确的,并且可以很容易地为python 2.x修改(参见注释)。
编辑:现在我想起来了,我们可以概括这一点。我要把
1 2 3 4 5 6 | 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) |
。
现在您可以用一个调用附加多个容器。但这有点棘手,因为用户可能会这样做:
1 | a(bag=1, basket=2, bag=3) |
这并不是很好,但是如果你想要以
1 2 3 4 5 6 7 8 9 10 | 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) |
。
这个适合你的用例吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | >>> 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 |