Python эквивалент PHP () и 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 есть что-то еще лучше, что устраняет необходимость в этом?

Это не очень 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 по крайней мере по трем пунктам: «явный лучше, чем неявный», «простой лучше, чем сложный», «если сложность реализации трудно объяснить, это плохая идея», может быть, больше (и действительно, если у вас достаточно опыта в Python, вы знаете, что такие вещи просто не выполняются). Я мог видеть, что это полезно для анализа отладчика или посмертного анализа или, возможно, для какой-то очень общей структуры, которая часто требует создания переменных с динамически выбранными именами и значениями, но это растяжение.

Если вы собираетесь использовать эти функции, вы должны хотя бы сохранить extract переменные, содержащиеся в небольших областях. Оберните их функциями, которые затем можно считать «черными ящиками». Основной причиной extract является то, что он помещает переменные в вашу таблицу символов таким образом, что это не ясно из проверки кода. Если вы сохраните эффекты этих переменных, локализованных на очень маленькую функцию, и объясните, что вы делаете с четким кодом и комментариями, это не так уж и важно.

Я боюсь, что в 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 явное лучше, чем неявное :

 a = 1 b = 2 # compact c = dict(a=a, b=b) # extract a, b = d['a'], d['b'] 

Стоит ли указывать, что extract() (и в меньшей степени, compact() ) является одной из самых «злых» функций PHP (наряду с register_globals и eval ), и их следует избегать?

extract делает намного сложнее определить, где была определена переменная. Когда сложнее отслеживать переменную до того места, где она была определена, сложнее проверить общие проблемы безопасности, такие как использование неинициализированных переменных или нефильтрованные переменные, которые возникли из пользовательского ввода.

compact не так уж плох, но если его использовать плохо, он все же может усложнить работу, чем в противном случае было бы увидеть, где элемент массива получает значение из переменной.

Эквивалентом extract() во многих других языках является ключевое слово. У Python теперь есть ключевое слово, хотя оно работает немного по-другому, что делает его не совсем похожим на extract() . Тем не менее, на других языках, таких как Javascript, ключевое слово также имеет плохую репутацию .

Я думаю, что лучшим советом было бы думать иначе – вместо того, чтобы пытаться подражать плохой функции 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 .

Я предполагаю, что эквивалент 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} 

Вы можете сделать это (хотя я бы предложил только экономно …) с функцией locals() , которая возвращает обновляемый dict . Пример:

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

Поэтому locals() будут «compact all» и locals().update() будет extract .

Удачи!