提问人:Turadg 提问时间:4/24/2009 最后编辑:Turadg 更新时间:2/23/2020 访问量:8957
Python 相当于 PHP 的 compact() 和 extract()
Python equivalent of PHP's compact() and extract()
问:
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 是否有更好的东西来消除对这个的需求?
答:
我猜等价的是 ,因为它是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}
恐怕 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']
评论
它不是很 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 经验,你就会知道这样的事情还没有完成)。我可以看到它对于调试器或事后分析很有用,或者对于某种非常通用的框架很有用,这些框架经常需要创建具有动态选择的名称和值的变量,但这是一个延伸。
评论
是否值得指出(在较小程度上,)是PHP最“邪恶”的功能之一(以及和),应该避免?extract()
compact()
register_globals
eval
提取
使确定变量的定义位置变得更加困难。当更难将变量追溯到定义变量的位置时,就更难检查常见的安全问题,例如使用未初始化的变量或源自用户输入的未过滤变量。
compact
并没有那么糟糕,但如果使用得不好,仍然会比从变量中查看数组成员的设置位置更加困难。
在许多其他语言中,关键字是等价物。Python 现在有一个关键字,尽管它的工作方式略有不同,使其不太像 .但是,在 Javascript 等其他语言中,该关键字的声誉也很差。extract()
with
with
extract()
with
我认为最好的建议是换个角度思考——与其试图模仿 PHP 的坏特性,不如想想其他方法,用简洁易读的代码做你想做的事情。
评论
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 一样丑陋。
您可以使用该函数执行此操作(尽管我建议仅谨慎...例:locals()
dict
$ python
Python 2.7.12 (default, Jul 1 2016, 15:12:24)
>>> locals().update({'derek':'anderson'})
>>> derek
'anderson'
>>>
所以将是“紧凑的”,并且是.locals()
locals().update()
extract
祝你好运!
评论
context = {c.a:1, c.b:2}; timeit.Timer('c.a+c.b', 'import __main__.context as c')
a
b