6

inforループコンテキストでリスト内包表記またはキーワードを使用する場合、つまり:

for o in X:
    do_something_with(o)

また

l=[o for o in X]
  • 背後にあるメカニズムはどのように機能しinますか?
  • 内のどの関数/メソッドをX呼び出しますか?
  • X複数の方法に準拠できる場合、優先順位は何ですか?
  • Xリスト内包表記が速くなるように、効率的に書く方法は?
4

6 に答える 6

10

、afaik、完全で正しい答え。

for、forループとリスト内包表記の両方で、を呼び出しiter()ますX。メソッドまたはメソッドがあるiter()場合は、iterableを返します。両方を実装する場合は、が使用されます。どちらも持っていない場合は取得します。X__iter____getitem____iter__TypeError: 'Nothing' object is not iterable

これは:を実装し__getitem__ます

class GetItem(object):
    def __init__(self, data):
        self.data = data

    def __getitem__(self, x):
        return self.data[x]

使用法:

>>> data = range(10)
>>> print [x*x for x in GetItem(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

これは実装の例です__iter__

class TheIterator(object):
    def __init__(self, data):
        self.data = data
        self.index = -1

    # Note: In  Python 3 this is called __next__
    def next(self):
        self.index += 1
        try:
            return self.data[self.index]
        except IndexError:
            raise StopIteration

    def __iter__(self):
        return self

class Iter(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        return TheIterator(data)

使用法:

>>> data = range(10)
>>> print [x*x for x in Iter(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

ご覧のとおり、イテレータを実装するには両方が必要であり、__iter__それによってイテレータが返されます。

それらを組み合わせることができます:

class CombinedIter(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        self.index = -1
        return self

    def next(self):
        self.index += 1
        try:
            return self.data[self.index]
        except IndexError:
            raise StopIteration

使用法:

>>> well, you get it, it's all the same...

ただし、一度に実行できるイテレータは1つだけです。OK、この場合、これを行うことができます:

class CheatIter(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        return iter(self.data)

__iter__しかし、あなたはの方法を再利用しているだけなので、それはごまかしですlist。より簡単な方法は、yieldを使用__iter__して、ジェネレーターにすることです。

class Generator(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        for x in self.data:
            yield x

これが私がお勧めする方法です。簡単で効率的。

于 2011-01-30T17:47:29.797 に答える
5

X反復可能でなければなりません。__iter__()イテレータオブジェクトを返すを実装する必要があります。イテレータオブジェクトはnext()、を実装する必要があります。これは、呼び出されるたびに次のアイテムを返すか、StopIteration次のアイテムがない場合はを発生させます。

リスト、タプル、ジェネレーターはすべて反復可能です。

プレーンforオペレータは同じメカニズムを使用することに注意してください。

于 2011-01-30T16:41:20.203 に答える
4

質問のコメントに答えるこの場合、ソースを読むことは最善の考えではないと言えます。コンパイルされたコード(ceval.c)の実行を担当するコードは、Pythonソースを初めて見る人にとってはそれほど冗長ではないようです。forループの反復を表すスニペットは次のとおりです。

   TARGET(FOR_ITER)
        /* before: [iter]; after: [iter, iter()] *or* [] */
        v = TOP();

        /*
          Here tp_iternext corresponds to next() in Python
        */
        x = (*v->ob_type->tp_iternext)(v); 
        if (x != NULL) {
            PUSH(x);
            PREDICT(STORE_FAST);
            PREDICT(UNPACK_SEQUENCE);
            DISPATCH();
        }
        if (PyErr_Occurred()) {
            if (!PyErr_ExceptionMatches(
                            PyExc_StopIteration))
                break;
            PyErr_Clear();
        }
        /* iterator ended normally */
        x = v = POP();
        Py_DECREF(v);
        JUMPBY(oparg);
        DISPATCH();

ここで実際に何が起こっているかを見つけるには、冗長性がそれほど良くない他のファイルの束に飛び込む必要があります。したがって、そのような場合、ドキュメントやSOのようなサイトが最初に行くべき場所であり、ソースは明らかにされた実装の詳細についてのみチェックされるべきだと思います。

于 2011-01-30T17:46:59.980 に答える
3

X反復可能なオブジェクトである必要があります。つまり、__iter__()メソッドが必要です。

したがって、for..inループまたはリスト内包表記を開始するには、firstX__iter__()メソッドを呼び出してイテレータオブジェクトを取得します。次に、そのオブジェクトのnext()メソッドは、が発生するまで反復ごとに呼び出され、StopIteration発生すると反復が停止します。

3番目の質問の意味と、イテレータが一度にメモリ内のリスト全体を作成するべきではないことを除いて、4番目の質問に意味のある答えを提供する方法がわかりません。

于 2011-01-30T16:42:44.093 に答える
2

たぶんこれは役に立ちます(チュートリアルhttp://docs.python.org/tutorial/classes.htmlセクション9.9):

舞台裏では、forステートメントがコンテナオブジェクトに対してiter()を呼び出します。この関数は、コンテナ内の要素に一度に1つずつアクセスするメソッドnext()を定義するイテレータオブジェクトを返します。要素がなくなると、next()はStopIteration例外を発生させ、forループを終了するように指示します。

于 2011-01-30T16:40:05.603 に答える
0

あなたの質問に答えるには:

背後にあるメカニズムはどのように機能しますか?

他の人がすでに述べたように、これは通常のforループで使用されるのとまったく同じメカニズムです。

X内のどの関数/メソッドを呼び出しますか?

以下のコメントに記載されているようにiter(X)、イテレータを取得するために呼び出します。Xメソッド関数が定義されている場合__iter__()、これはイテレータを返すために呼び出されます。それ以外の場合、Xを定義すると__getitem__()、これは繰り返し呼び出されて繰り返されXます。こちらのPythonドキュメントを参照してください:http iter()//docs.python.org/library/functions.html#iter

Xが複数の方法に準拠できる場合、優先順位は何ですか?

ここにあなたの質問が正確に何であるかはわかりませんが、Pythonにはメソッド名を解決する方法に関する標準のルールがあり、それらはここで守られています。これについての議論は次のとおりです。

新しいスタイルのPythonクラスのメソッド解決順序(MRO)

リスト内包表記が速くなるように、効率的なXを作成するにはどうすればよいですか?

Pythonのイテレータとジェネレータについてもっと読むことをお勧めします。クラスサポートの反復を行う簡単な方法の1つは、iter()のジェネレーター関数を作成することです。ジェネレータについての説明は次のとおりです。

http://linuxgazette.net/100/pramode.html

于 2011-01-30T17:00:53.340 に答える