私はこのようなテキストファイルを持っています:
11
2
3
4
11
111
Python 2.7を使用して、それを行のリストのリストに変換したいと思います。ここで、改行は内側のリストの項目を分割し、空の行は外側のリストの項目を分割します。そのようです:
[["11","2","3","4"],["11"],["111"]]
そして、この目的のために、開いているファイルオブジェクトを渡すと、一度に1つずつ内部リストを生成するジェネレーター関数を作成しました。
def readParag(fileObj):
currentParag = []
for line in fileObj:
stripped = line.rstrip()
if len(stripped) > 0: currentParag.append(stripped)
elif len(currentParag) > 0:
yield currentParag
currentParag = []
これは問題なく機能し、リスト内包表記内から呼び出すことができ、目的の結果が得られます。しかし、その後、同じことをより簡潔に使用できる可能性があることに気付きitertools.takewhile
ました(ジェネレーター関数をジェネレーター式として書き直すためですが、ここではそのままにしておきます)。これは私が試したものです:
from itertools import takewhile
def readParag(fileObj):
yield [ln.rstrip() for ln in takewhile(lambda line: line != "\n", fileObj)]
この場合、結果のジェネレーターは1つの結果(期待される最初の結果、つまり["11","2","3","4"]
)のみを生成します。そのnext
メソッドを再度呼び出すtakewhile(lambda line: line != "\n", fileObj)
と、ファイルの残りの部分で再度評価され、別のリストが生成されることを期待していました。しかし、いいえ:StopIteration
代わりに入手しました。したがって、式はジェネレーターオブジェクトが作成されたときに一度だけ評価され、結果のジェネレーターオブジェクトのメソッドtake while
を呼び出すたびには評価されていないと推測しました。next
この仮定から、ジェネレーター関数をもう一度呼び出したらどうなるのだろうと思いました。その結果、新しいジェネレーターオブジェクトが作成され、1つの結果(予想される2番目の結果)が生成されてから、私["11"]
にStopIteration
返されました。したがって、実際には、これをジェネレーター関数として記述すると、通常の関数として記述しreturn
、リストを作成する代わりに編集した場合と同じ結果が得られyield
ます。
ジェネレータの代わりに使用する独自のクラスを作成することで、この問題を解決できると思います(この質問に対するJohn Millikinの回答のように)。しかし、要点は、元のジェネレーター関数(おそらくジェネレーター式でさえ)よりも簡潔なものを書きたいと思っていたということです。誰かが私が間違っていることとそれを正しくする方法を教えてもらえますか?