【问题标题】:Python convenient passing of dictionary arguments to functionPython方便地将字典参数传递给函数
【发布时间】:2015-01-21 11:29:25
【问题描述】:

我曾想过以某种方式将字典附加到本地范围,但是我看到在 SO 上提出了类似的问题 - 通常回答是“不要这样做!”。我将说明我的问题并欢迎任何解决此问题的建议。

如果有一个选项字典(从 JSON 中读取,所以不希望对它进行过多的处理),我决定按如下方式传递它;

def testParse(dataObj, userOptions):

    # Merge default with passed options taking prescidence
    defaultOpts = {

        'boxheight' : 200,
        'boxwidth'  : 100,
        'padding'   : 150

    }
    opt = dict(userOptions.items() | defaultOpts.items())

问题是;有没有办法使用键将字典中的每个值附加到本地范围,而不是复制整个字典

boxheight = opt['boxheight']

等等,或者每次我提到它时都写opt['boxheight']。我可以循环 opt 字典并以编程方式分配值吗?

我绝不会依附于所概述的方法,但所有选项都会在某些时候在局部表达式中使用,并且它们从一开始就作为字典存在。非常感谢您的建议。

[免责声明:只使用 Python 几天]

【问题讨论】:

  • 不,没有办法对局部变量执行此操作。字典中有多少项目?我建议明确分配。
  • 解决这个问题的最简单方法是给子函数添加关键字参数,然后将字典解压到调用中(例如,def func(padding, **kwargs) 然后func(**opt) 将使padding 在@ 本地可用987654328@ 并将其他所有内容打包到 kwargs)。
  • @jonrsharpe - 漂亮!
  • 另一种选择是使用命名空间对象class Namespace: pass。这可以用作opt = Namepsace(); vars(opt).update(defaultOptions); vars(opt).update(userOptions)。之后,您可以使用 opt.boxheight 访问 opts,您可能会发现它的语法噪音较小。
  • 作为一个侧节点,如果一个键同时出现在userOptionsdefaultOpts 中,您构建合并字典的方式会导致选择任意值。

标签: python python-3.x dictionary scope


【解决方案1】:

好的,感谢@jonrshapre 的评论,我有以下解决方案

# user options
userOps = { 'name' : 'joe', 'age' : 21 }
data = (1,2)

# default options specified as function argument
def _func(data, name, lovesSO = True, **kwargs):

    print(data)
    print(name)
    print(lovesSO)
    print(kwargs)

# Call
_func(data, **userOps)    

# OUTPUTS
# (1,2)
# joe
# True
# {'age' : 21}

使用这种方法付出的代价似乎是有点不合常规的调用语法(尽管正如 cmets 中所指出的,这对于像我这样的新手来说是不寻常的)。然而,这可以通过定义来解决

def func(data, options): _func(data, **options)

或基于@Sven Marnach 的评论的另一种解决方案;

# Utility options class
class Options:
    def __init__(self, defaults, user_opts):
        vars(self).update(defaults)
        vars(self).update(user_opts)

def func2(data, userOps):

    opt = Options({ 'lovesSO' : True}, userOps)

    print(data)
    print(opt.name)
    print(opt.lovesSO)

# Call    
func2(data, userOps)

# OUTPUT
# (1, 2)
# joe
# True

这有定义帮助类的缺点,但好处是可以通过opt. 前缀清楚地知道哪些变量是用户可定义的选项。另外调用语法很自然。

在这两种情况下,未使用的用户选项都存储为 kwargs 字典(在第一种情况下)或 opt 字典中未使用的条目。

我个人决定选择第二种解决方案。

【讨论】:

  • “有点不合常规的调用语法” 似乎不准确 - *** 在惯用的 Python 中被广泛使用。另请注意,这些将以不同的方式使用 - 对于 Sven,您将传递单个 Namespace 对象 to func2,其中包含所有用户选项,而不是创建 Namespace 内部函数。
  • @jonrsharpe。回复:斯文的方法;如果我在 func2 之外定义命名空间对象,那么默认选项将覆盖用户选项,不是吗?看来我需要进行某种密钥检查?
  • 我建议在全局级别定义Namespace 类,并为其提供一个接受默认值和用户选项的构造函数。这样,函数内部的样板就基本消失了。
  • 不会func2 中更新Namespace - 如果您有本地默认值以防某个属性丢失,您可以这样做,例如lovesSO = getattr(opts, "lovesSO", True)。请注意,如果您只有一个值要设置 - setattr(opts, "lovesSO", True),您也可以使用 setattr 来更新命名空间。
  • @Sven Marnach - 更好吗?来回抱歉 - 仍在学习!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-30
  • 2015-01-23
  • 1970-01-01
  • 2010-09-24
  • 2017-10-01
相关资源
最近更新 更多