6

ネストされたスコープ規則とリスト内包表記の組み合わせに悩まされていると思います。 Jeremy Hylton のブログ投稿は原因について示唆に富んでいますが、CPython の実装を十分に理解していないため、これを回避する方法を理解することができません。

これは(複雑すぎる?)例です。人々がそれをデモする簡単なものを持っているなら、私はそれを聞きたい. 問題: next() を使用したリスト内包表記は、最後の反復の結果で埋められます。

編集:問題:

これで正確に何が起こっているのですか?どうすれば修正できますか? 標準の for ループを使用する必要がありますか? 明らかに、関数は正しい回数実行されていますが、リスト内包表記は各ループの結果ではなく、最終的な値で終わります。

いくつかの仮説:

  • 発電機?
  • リスト内包表記の遅延充填?

コード

import itertools
def digit(n):
    digit_list = [ (x,False) for x in xrange(1,n+1)]
    digit_list[0] = (1,True)
    return itertools.cycle ( digit_list)
>>> D = 桁(5)
>>> [D.next() for x in range(5)]
## このリスト内包表記は期待どおりに機能します
[(1, True), (2, False), (3, False), (4, False), (5, False)]
class counter(object):
    def __init__(self):
        self.counter = [ digit(4) for ii in range(2) ] 
        self.totalcount=0
        self.display = [0,] * 2
    def next(self):
        self.totalcount += 1
        self.display[-1] = self.counter[-1].next()[0]
        print self.totalcount, self.display
        return self.display

    def next2(self,*args):
        self._cycle(1)
        self.totalcount += 1
        print self.totalcount, self.display
        return self.display

    def _cycle(self,digit):
        d,first = self.counter[digit].next()
        #print digit, d, first
        #print self._display
        self.display[digit] = d
        if first and digit > 0:
            self._cycle(digit-1)


C = counter()
[C.next() for x in range(5)]
[C.next2() for x in range(5)]

出力

[44]: [C.next() for x in range(6)]
1 [0, 1]
2 [0, 2]
3 [0, 3]
4 [0, 4]
5 [0, 1]
6 [0, 2]
出力[44]: [[0, 2], [0, 2], [0, 2], [0, 2], [0, 2], [0, 2]]

[45]: [C.next2() for x in range(6)]
7 [0, 3]
8 [0, 4]
9 [1, 1]
10 [1, 2]
11 [1, 3]
12 [1, 4]
出力[45]: [[1, 4], [1, 4], [1, 4], [1, 4], [1, 4], [1, 4]]

# これは [[0,3],[0,4]....[1,4]] または類似
4

2 に答える 2

15

問題は、このリストへの参照(コピーではない)return self.displayを返すことです。最終的には、各要素が self.display への参照であるリストになります。説明のために、次を見てください。

>>> a = [1,2]
>>> b = [a,a]
>>> b
[[1, 2], [1, 2]]
>>> a.append(3)
>>> b
[[1, 2, 3], [1, 2, 3]]

おそらく、のようなものを使用したいと思うでしょうreturn self.display[:]

于 2008-10-22T13:50:47.130 に答える
4

これを少しリファクタリングしてもよろしいですか?

def digit(n):
    for i in itertools.count():
        yield (i%n+1, not i%n)

しかし、単純なイテレータとしてすべてを実装する場合、実際には必要ありません。

def counter(digits, base):
    counter = [0] * digits

    def iterator():
        for total in itertools.count(1):
            for i in range(len(counter)):
                counter[i] = (counter[i] + 1) % base
                if counter[i]:
                    break
            print total, list(reversed(counter))
            yield list(reversed(counter))

    return iterator()

c = counter(2, 4)
print list(itertools.islice(c, 10))

印刷を取り除きたい場合 (デバッグですか?)、while ループを使用します。

reversedリストのコピーを返すため、これは偶然にも最初の問題も解決します。

ああ、今はゼロベースです ;)

于 2008-10-23T21:34:09.580 に答える