Функция __getitem__
- это способ моделирования словаря или списка (или, точнее, любого отображения или последовательности).
Справочная документация для последовательностей и отображений находится в Data model, но лучшим местом для начала является, вероятно, модуль collections.abc
и ссылки оттуда.
Резюмируя основную идею, когда вы пишете код, как это:
foo[bar]
Python переводит его в *:
foo.__getitem__(bar)
Там нет ничего плохого с определением __getitem__
для имитации dict
.
И сделать это, чтобы создать объект, который рассматривает его атрибуты как элементы dict, является таким общим шаблоном, что он имеет имя («attrdict»).
Однако использование eval
является почти всегда неправильным.Итак, правильная вещь, чтобы сделать работу eval
, как правило, прямо в том, что вы поступаете правильно, но неправильно в том, что вы используете eval
в первую очередь.
В вашем конкретном случае, нет никаких оснований использовать eval
в первую очередь. Вместо этого:
eval("color=='green'",new_dict)
Просто сделай это:
new_dict['color']=='green'
Одна из причин Python новички (особенно те, кто вырос на старых версиях PHP, Tcl или JavaScript) часто требуется использовать eval
является получить выражение, которое они могут легко пройти. Но в Python (и, если на то пошло, современные PHP и JS), функции являются первоклассными значениями, так же легко переносится как строки, и, в отличие от строк, конечно, они могут быть вызваны. Вы можете создавать именованные или лямбда-функции или использовать partial
, закрыть любые локальные переменные, которые вы хотите, и т. Д.
Существует почти ничего, что можно сделать со строкой, которую вы не можете сделать с помощью функции, кроме, конечно, для открытия зияющего отверстия для обеспечения безопасности, замедления производительности и затруднения отладки.
Таким образом, вместо того, чтобы что-то вроде этого:
expr = "color=='green'"
# ...
eval(expr, new_dict)
... просто это сделать:
expr = lambda x: x.color=='green'
# ...
expr(new_dict)
В вас отредактированный вопрос:
Вот почему Eval является используется в программе: представьте, что вы получили 20 объектов myStuff в списке mylist, и вы хотите отфильтровать их по желтому цвету, тогда можно просто вызвать [n для n в mylist, если eval (query, Dummy (n)] с `query =" color == 'yellow' ".
Таким образом, вы, вероятно делаете что-то вроде этого:
query = "color=={}'.format(color)
# ...
[n for n in mylist if eval(query, Dummy(n)]
Но вы могли бы так же легко сделать это:
[n for n in mylist if n.color == color]
Даже если вам нужно что-то более динамичное, вы можете строить функции динамически, еще проще, чем строки:
query = lambda n: n.color == color
[n for n in mylist if query(n)]
В самом деле, если вы действительно хотите, вы можете даже сделать это полностью функциональны:
filter(compose(partial(operator.eq, color), attrgetter('color')), mylist)
Но большая вещь о Python является то, что вы не должны идти полностью функциональным или полностью императив, вы можете написать что-то на полпути между - или 25% или 75%, что бы ни было проще читать и писать.
Тем:
Или это плохо использовать вышеупомянутый метод, потому что никто не знает, как реализован метод Eval и, следовательно, код может придумать некоторые странные ошибки в будущем ?
Нет, это почти никогда проблема.
Во-первых, documentation for eval
, как правило, достаточно, чтобы точно предсказать, что он будет делать, и все реализации Python должны следовать этой документации.
В редких случаях, когда вы нуждаетесь в знании больше, все основные реализации имеют открытый исходный код, поэтому вы можете просто прочитать код. Например, вы можете просматривать код CPython 3.3 онлайн here **
* Это не совсем точно. реальный код фактически ищет __getitem__
в классе, а не объекте (немного по-другому для старого стиля и новых классов в 2.x), а также обрабатывает типы расширений из модулей C/Java-пакетов/независимо от того, что подходит для вашей реализации Python, сделок с фрагментами (по-разному в 2.x против 3.x) и т. д. Но это основная идея.
** eval
кода постепенно переработан на протяжении многих лет, так что в этот момент вы могли бы в значительной степени переописать eval
в нескольких строках чистого Python с помощью ast
модуля и друзей, или несколько строк C с использованием PyEval*
, поэтому вам трудно указать точную строку кода, чтобы не задумываться о том, какую реализацию и версию вы волнуете.
Почему вы используете 'eval' таким образом? Что не так с 'd ['color'] == 'green''? – Blender
Совершенно разумным вопросом является вопрос о том, как работает * eval * (т. Е. Оценки выполняются в пространстве имен, которое может быть произвольным отображением с использованием \ _ \ _ getitem \ _ \ _). Этот метод является универсальным и позволяет легко реализовать последовательные вычисления, такие как те, которые используются в электронных таблицах (что нелегко сделать с помощью обычного словаря). –
@ RaymondHettinger: Да, разумно задаться вопросом, как работает 'eval', и на самом деле было бы здорово, если бы кто-то написал учебник, который ищет OP. Но это не меняет того факта, что, как и 99% людей, у которых есть проблема с 'eval', OP не должен был использовать его здесь. Вот почему всегда стоит спросить: «Почему вы хотите использовать« eval »здесь?» первый. Наихудший сценарий заключается в том, что у них есть хороший ответ (который может включать «потому что я хочу понять« eval »), что делает их вопрос более полезным для будущих читателей, не так ли? – abarnert