Python 相当于 PHP 的 compact() 和 extract()

Python equivalent of PHP's compact() and extract()

提问人:Turadg 提问时间:4/24/2009 最后编辑:Turadg 更新时间:2/23/2020 访问量:8957

问:

compact() 和 extract() 是我发现非常方便的 PHP 函数。compact() 获取符号表中的名称列表,并创建一个仅包含其值的哈希表。提取则相反。例如,

$foo = 'what';
$bar = 'ever';
$a = compact('foo', 'bar');
$a['foo']
# what
$a['baz'] = 'another'
extract(a)
$baz
# another

有没有办法在 Python 中做同样的事情?我环顾四周,最接近的是这个线程,它似乎对它不屑一顾。

我知道 locals()、globals() 和 vars(),但我如何才能方便地选择它们值的子集?

Python 是否有更好的东西来消除对这个的需求?

php python 字典

评论

4赞 pantsgolem 4/24/2009
好吧,我想我明白是什么让我感到困惑了。看起来您的第 3 行应该是“$a = compact('foo', 'bar');”。
0赞 Turadg 9/10/2009
哎呀,谢谢。我刚刚纠正了它。
0赞 Paul Biggar 9/28/2009
我能问一下你为什么觉得它们很方便吗?我看不出它们有什么好处,不能使用哈希表更干净地实现。
0赞 Turadg 12/31/2009
哈希表可能在语义上更干净,可以说更不容易出错,但我发现上面的内容读写起来更干净。感谢所有的回答!
0赞 intuited 5/29/2010
在运行测试时,这在 python 中似乎很有用,因为除非我弄错了,否则无法提供上下文字典来计时。定时器。例如,如果可以提取到测试上下文中,则会变得更加简单。context = {c.a:1, c.b:2}; timeit.Timer('c.a+c.b', 'import __main__.context as c')ab

答:

2赞 Adam 4/24/2009 #1

我猜等价的是 ,因为它是extract($x)globals().update(x)compact()vars()

>>> foo, bar, baz = 1, 2, 3
# extract
>>> globals().update({"foo": 4, "qux": 5})
>>> foo
4
>>> qux
5
# compact
>>> d = dict((k, v) for k, v in vars().iteritems() if k in ["foo", "bar"])
>>> d
{'bar': 2, 'foo': 1}
10赞 Ferdinand Beyer 4/24/2009 #2

恐怕 Python 中没有等价物。在某种程度上,您可以使用(和传递)来模拟它们的效果:locals

>>> def compact(locals, *keys):
...     return dict((k, locals[k]) for k in keys)
...
>>> a = 10
>>> b = 2
>>> compact(locals(), 'a', 'b')
{'a': 10, 'b': 2}

>>> def extract(locals, d):
...     for k, v in d.items():
...         locals[k] = v
...
>>> extract(locals(), {'a': 'foo', 'b': 'bar'}
>>> a
'foo'
>>> b
'bar'

尽管如此,我不认为这些功能“非常方便”。动态的全局/局部变量是邪恶的,容易出错——PHP的人在劝阻register_globals时就知道了这一点。根据我的经验,很少有有经验的 PHP 程序员或主要框架使用 or .compact()extract()

在 Python 中,显式比隐式更好

a = 1
b = 2
# compact
c = dict(a=a, b=b)

# extract
a, b = d['a'], d['b']

评论

1赞 Turadg 1/7/2010
我完全支持明确,但为什么它必须是多余的?这难道不是不那么容易出错吗?c = 紧凑(a, b)
13赞 David Z 4/24/2009 #3

它不是很 Pythonic,但如果你真的必须这样做,你可以像这样实现:compact()

import inspect

def compact(*names):
    caller = inspect.stack()[1][0] # caller of compact()
    vars = {}
    for n in names:
        if n in caller.f_locals:
            vars[n] = caller.f_locals[n]
        elif n in caller.f_globals:
            vars[n] = caller.f_globals[n]
    return vars

过去可以这样实现,但在现代 Python 解释器中,这似乎不再起作用了(并不是说它曾经“应该”工作,真的,但 2009 年实现的一些怪癖让你侥幸逃脱):extract()

def extract(vars):
    caller = inspect.stack()[1][0] # caller of extract()
    for n, v in vars.items():
        caller.f_locals[n] = v   # NEVER DO THIS - not guaranteed to work

如果你真的觉得你需要使用这些功能,你可能做错了什么。它似乎至少在三个方面违背了 Python 的理念:“显式比隐式好”、“简单比复杂好”、“如果实现难以解释,那就是一个坏主意”,也许更多(实际上,如果你有足够的 Python 经验,你就会知道这样的事情还没有完成)。我可以看到它对于调试器或事后分析很有用,或者对于某种非常通用的框架很有用,这些框架经常需要创建具有动态选择的名称和值的变量,但这是一个延伸。

评论

0赞 Luis Mauricio 2/14/2022
我有一个日志记录用例,有时我需要收集 x 个变量并用紧凑记录它们,而不是重复自己做 {a:a, b:b, c:c},我记得有一种语言你可以说 {a, b, c} 并会自动创建带有值的字典,不记得是哪个。
9赞 thomasrutter 4/24/2009 #4

是否值得指出(在较小程度上,)是PHP最“邪恶”的功能之一(以及和),应该避免?extract()compact()register_globalseval

提取使确定变量的定义位置变得更加困难。当更难将变量追溯到定义变量的位置时,就更难检查常见的安全问题,例如使用未初始化的变量或源自用户输入的未过滤变量。

compact 并没有那么糟糕,但如果使用得不好,仍然会比从变量中查看数组成员的设置位置更加困难。

在许多其他语言中,关键字是等价物。Python 现在有一个关键字,尽管它的工作方式略有不同,使其不太像 .但是,在 Javascript 等其他语言中,该关键字的声誉也很差extract()withwithextract()with

我认为最好的建议是换个角度思考——与其试图模仿 PHP 的坏特性,不如想想其他方法,用简洁易读的代码做你想做的事情。

评论

1赞 Ferdinand Beyer 4/24/2009
请注意,Python 中的“with”语句与 JavaScript 中的语义完全不同,并且不会更改任何“变量范围”。此外,这是一个相当新的功能,当然没有不好的声誉。不过,您对 JavaScript-“with” 是正确的。
0赞 Ry- 7/11/2013
我把它编辑到不再有意义的地步,因为它不适合一条评论,但所有这些都很重要。之后我没有回滚它,因为它已转换为评论。我删除了它,因为我觉得它没有回答问题,因为正如你评论的第一句话所写的那样,你只是在指出一些东西。
0赞 thomasrutter 7/11/2013
好吧,有 8 个赞成票,没有反对票,似乎有些人认为它应该在这里???
0赞 thomasrutter 8/6/2013
有时,问题的最佳答案不是从字面上回答问题,而是指出整个方法中的问题,作为问题的前提。这就是我在这里证明这个答案的合理性。
0赞 Zippp 7/9/2015
使用“compact”作为一种非常紧凑的方式来组装一种字典,以便将其从特定的控制器/操作(MVC)传递到视图中是一种非常简单的方法,并且在某些领先的PHP框架(Symfony)中是一种常见的做法,因此不要认为将其用于适当的目的有任何错误
3赞 Elf Sternberg 5/15/2009 #5

PHP 在 Python 中的紧凑函数(适用于 2.6;不保证适用于早期版本的 Python):

import inspect
def compact(*args):
    return dict([(i, inspect.currentframe().f_back.f_locals.get(i, None)) 
                  for i in args])

我写过关于这个问题的更广泛的文章:Python 可以和 PHP 一样丑陋

0赞 keredson 9/24/2016 #6

您可以使用该函数执行此操作(尽管我建议仅谨慎...例:locals()dict

$ python
Python 2.7.12 (default, Jul  1 2016, 15:12:24) 
>>> locals().update({'derek':'anderson'})
>>> derek
'anderson'
>>> 

所以将是“紧凑的”,并且是.locals()locals().update()extract

祝你好运!

评论

0赞 martineau 2/14/2020
文档明确指出“不应修改本词典的内容”。