この__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 で育った人) がしばしば使用したいと思う理由の 1 つeval
は、簡単に渡すことができる式を取得することです。しかし、Python (そして、最新の PHP と JS) では、関数は第一級の値であり、文字列と同じくらい簡単に渡すことができます。もちろん、文字列とは異なり、関数は呼び出し可能です。名前付き関数またはラムダ関数を作成したり、 を使用したり、必要partial
なローカル変数を閉じたりすることができます。
関数でできない文字列でできることはほとんどありません。もちろん、大きなセキュリティ ホールを開いたり、パフォーマンスを低下させたり、デバッグを妨げたりすることは別として。
したがって、次のような代わりに:
expr = "color=='green'"
# ...
eval(expr, new_dict)
…これを行うだけです:
expr = lambda x: x.color=='green'
# ...
expr(new_dict)
あなたが編集した質問で:
プログラムで eval が使用される理由は次のとおりです。リスト mylist に myStuff の 20 個のオブジェクトがあり、それらを黄色でフィルター処理したいとします。次に、[ n for n in mylist if 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 メソッドがどのように実装されているかを実際に誰も知らないため、コードで将来奇妙なエラーが発生する可能性があるため、上記のメソッドを使用するのは悪いことですか?
いいえ、それはほとんど問題になりません。
まず、 のドキュメントeval
は通常、それが何をするかを正確に予測するのに十分であり、すべての Python 実装はそのドキュメントに従う必要があります。
詳細を知る必要があるまれなケースでは、主要な実装はすべてオープン ソースであるため、コードを読むだけで済みます。たとえば、ここでCPython 3.3 コードをオンラインで参照できます。**
* これは完全に正確ではありません。実際のコードは実際に__getitem__
はオブジェクトではなくクラスを検索し (古いスタイルのクラスと 2.x の新しいクラスでは少し異なります)、C モジュール/Java パッケージ/Python 実装に適したものから拡張型を処理します。スライス (2.x と 3.x では異なる) など。しかし、それが基本的な考え方です。
**eval
コードは何年にもわたって徐々にリファクタリングされてきたので、この時点でeval
、モジュールとその仲間を使用して純粋な Python の数行ast
、または関数を使用して C の数行でほとんど再実装できるため、指摘PyEval*
するのは困難です。関心のある実装とバージョンを知らなくても、コードの正確な行から開始できます。