【问题标题】:Actual name of the passed parameter传递参数的实际名称
【发布时间】:2013-01-15 04:19:42
【问题描述】:

是否可以在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 等其他脚本语言中执行此操作。
  • 更是如此,以防两种建模方式不同或可以采用任何不同的方式。

谢谢。

【问题讨论】:

  • 我不确定我是否理解这个问题。如果你做def a(name)name参数的名字是"name",不是吗?你还想要什么名字?如果您的意思是用于调用函数的变量的名称,那么可能没有任何这样的变量。如果我打电话给a("foo"),有没有名字? a(foo + "bar") 怎么样?至于您想要的行为,为什么不将适当的列表传递给函数?
  • 我希望它根据我是通过 bag_list 还是 basket_list 来分叉到正确的列表中

标签: python parameters


【解决方案1】:

这是可能的 - 但我认为这是一种肮脏的黑客行为。看完我的解决方案后,如果你真的想走这条路,你应该退后一步,三思而后行。

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

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

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

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

【讨论】:

    【解决方案2】:

    我认为您遇到的问题是论点的差异。有关键字参数,其中名称由调用者和简单的位置参数显式声明。你可以这样做,

    def a(**kwargs):
        if 'bag' in kwargs:
             dist_list = ID['bag']
        else:
            dist_list = ID['basket']
    

    你必须像这样传递变量,

    a(bag=...)
    

    或者如果您想查看参数startswith bag 或 basket 是否可以,

    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`')
    

    但是你有确定哪个键以bag或basket开头的问题,所以我可能会这样做,

    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`')
    

    【讨论】:

    • 是的,我想我可以直接这样做:codea(bag_list=bag_list) codea(basket_list=basket_list)
    【解决方案3】:

    这样的东西适合你的用例吗?

    >>> 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
    

    【讨论】:

    • >>> test(dist_list = bag_list) {'dist_list': bag_list}
    • @ShyamSunder 我已经编辑了我的答案 - 你想实现这样的目标吗?
    【解决方案4】:

    一般来说,你想要的是不可能的,因为 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)
    

    【讨论】:

    • 只是出于兴趣,您使用len(kwargs.keys()) 而不是len(kwargs) 有什么原因吗?
    • @AlexL,没有理由......至少没有充分的理由!我现在将对其进行编辑以缩短它。感谢您指出这一点。
    猜你喜欢
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多