0

是否可以在 Python 中获取传递参数的名称?

具体来说,我希望能够做到这一点:

def a(name):
    print "the actual passed parameter is %s" %(???)

它解决了什么?

因此,如果我需要在袋子和篮子中分发硬币,比如 bag_list 和 basket_list,我不需要发送一个明确的标识符,比如“袋子”或“篮子”

这就是我目前的工作方式。我目前正在为此目的使用(全局)字典-

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中得到全面回答,但我正在重新发布

  • 以防万一有一些修改&
  • 是否可以在其他脚本语言(如 Perl 或 Tcl)中执行此操作。
  • 更重要的是,以防两种建模方式不同或可以采用任何不同的方式进行处理。

谢谢。

4

4 回答 4

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

通过我的示例,您还可以看到这种方法的缺点。

  • 如果直接传入字符串而不赋值变量,则无法确定名称
  • 如果您对同一个变量有多个引用,您将永远不知道会选择哪个名称

对于后一个问题,您当然可以实现一些逻辑来应对它 - 或者这对您来说根本没有问题。

于 2013-01-31T06:34:23.027 回答
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`')
于 2013-01-31T06:16:06.967 回答
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
于 2013-01-31T06:10:41.350 回答
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永远不会发生,因为将bag3字典中设置为。(可能有一种棘手的方法可以用具有重载函数的自定义类替换字典,但这种方法很疯狂……我不推荐使用那么棘手的代码。)

它不是那么好,但如果你想要以开头的名字任何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)
于 2013-01-31T06:12:02.290 回答