compact()和extract()是PHP中的函数我觉得非常方便。 compact()获取符号表中的名称列表,并仅使用其值创建哈希表。提取物恰恰相反。如,
$foo = 'what';
$bar = 'ever';
$a = compact('foo', 'bar');
$a['foo']
# what
$a['baz'] = 'another'
extract(a)
$baz
# another
有没有办法在Python中做同样的事情?我环顾四周,最接近的是this thread,似乎对它不屑一顾。
我知道locals(),globals()和vars(),但我怎样才能轻松选择其值的一个子集?
Python是否有更好的东西可以消除对此的需求?
答案 0 :(得分:10)
它不是非常Pythonic,但如果你真的必须:
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
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
我已经使用了很多这些实现,并且它们可以工作,但不支持从技术上修改f_locals
。
但是说真的,如果你真的觉得你需要使用这些功能,你可能会采取错误的方式。它似乎至少在三个方面与Python's philosophy相反:“明确比隐含更好”,“简单比复杂更好”,“如果实施难以解释,这是一个坏主意”,或许更多(实际上,如果你有足够的Python经验,你就知道这样的事情还没有完成。我可以看到它对于调试器或事后分析很有用,或者可能对某些非常通用的框架有用,它经常需要创建具有动态选择的名称和值的变量,但这只是一个延伸。 / p>
如果要使用这些函数,至少应将extract
ed变量保留在小范围内。将它们包装在您可以认为是“黑盒子”的功能中。 extract
错误的主要原因是它以一种在检查代码时不明确的方式将变量放入符号表中。如果你将这些变量的影响本地化为一个非常小的函数,并用明确的代码和注释来解释你正在做什么,那就不是一个大问题。
答案 1 :(得分:9)
我担心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程序员或主要框架使用compact()
或extract()
。
在Python中,explicit is better than implicit:
a = 1
b = 2
# compact
c = dict(a=a, b=b)
# extract
a, b = d['a'], d['b']
答案 2 :(得分:6)
值得指出的是extract()
(在较小程度上,compact()
)是PHP最“邪恶”的特征之一(以及register_globals
和{{1 (),应该避免吗?
extract
使确定变量定义的位置变得更加困难。当难以将变量追溯到定义的位置时,更难以检查常见的安全问题,例如使用未初始化的变量或源自用户输入的未过滤变量。
compact
并没有那么糟糕,但如果使用得不好,仍然会比查看从变量设置数组成员的位置更困难。
许多其他语言中的eval
相当于extract()
个关键字。 Python现在有一个with
关键字,但它的工作方式略有不同,使其与with
不太相似。但是,在其他语言(例如Javascript)中,extract()
关键字also has a poor reputation。
我认为最好的建议是以不同的方式思考 - 而不是试图模仿PHP的一个不好的功能,想一想用简洁易读的代码做你想做的事情的其他方法。
答案 3 :(得分:3)
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 can be just as ugly as PHP。
答案 4 :(得分:2)
我认为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}
答案 5 :(得分:1)
你可以使用locals()
函数执行此操作(尽管我只建议谨慎......),该函数返回可更新的dict
。例如:
$ python
Python 2.7.12 (default, Jul 1 2016, 15:12:24)
>>> locals().update({'derek':'anderson'})
>>> derek
'anderson'
>>>
因此locals()
将是“紧凑的全部”,locals().update()
将是extract
。
祝你好运!