3

こんにちは、私は Python の初心者で、助けが必要です。次のコードを書き留めました。

 try:
  it = iter(cmLines)
  line=it.next()
  while (line):
    if ("INFERNAL1/a" in line) or ("HMMER3/f" in line) :
      title = line
      line = it.next()
      if word2(line) in namesList: //if second word in line is in list
        output.write(title)
        output.write(line)
        line = it.next()
        while ("//" not in line):
          output.write(line)
          line = it.next()
        output.write(line)
    line = it.next()
except Exception as e:
  print "Loop exited becuase:"
  print type(e)
  print "at " + line
finally:
  output.close()
  1. ループが終了すると、ループが停止したことを通知する例外が常にスローされます。途中で終了しませんでしたが。どうすればそれを止めることができますか?

  2. 私のコードを書くためのより良い方法はありますか? よりスタイリッシュなもの。多くの情報を含む大きなファイルがあり、必要な情報だけを取得しようとしています。情報のすべてのスライスは次の形式です。

    Infernal1/a ...
    Name someSpecificName
    ...
    ...
    ...
    ...
    // 
    

ありがとうございました

4

5 に答える 5

2

RocketDonkey の答えは的確です。繰り返しの方法が複雑なため、ループでこれを行う簡単な方法はないforため、明示的に を処理する必要がありますStopIteration

ただし、問題を少し考え直すと、これを回避する方法が他にもあります。たとえば、簡単なステート マシンは次のとおりです。

try:
    state = 0
    for line in cmLines:
        if state == 0:
            if "INFERNAL1/a" in line or "HMMER3/f" in line:
                title = line
                state = 1
        elif state == 1:
            if word2(line) in NamesList:
                output.write(title)
                output.write(line)
                state = 2
            else:
                state = 0
        elif state == 2:
            output.write(line)
            if '//' in line:
                state = 0
except Exception as e:
    print "Loop exited becuase:"
    print type(e)
    print "at " + line
finally:
    output.close()

あるいは、サブジェネレーター ( yield from foo()3.3 を使用している場合は経由for x in foo(): yield x、そうでない場合は経由) にデリゲートするジェネレーター関数を作成することも、特に問題をより高いレベルで再考する場合は、他のさまざまな可能性を作成することもできます。

それはあなたがここでやりたいことではないかもしれませんが、少なくとも「このwhileループと 2 つの明示的なnext呼び出しをループに変えることはできforますか?」ということについて考える価値は通常あります。読みにくい。」

try補足として、 /finallywithステートメントに置き換えることで、おそらく物事を単純化できます。これの代わりに:

output = open('foo', 'w')
try:
    blah blah
finally:
    output.close()

これを行うことができます:

with open('foo', 'w') as output:
    blah blah

または、output通常のファイルでない場合でも、最後の 4 行を次のように置き換えることができます。

with contextlib.closing(output):
    blah blah
于 2013-01-23T01:03:20.917 に答える
1

を呼び出すとline = it.next()、何も残っていない場合にStopIteration例外が発生します。

>>> l = [1, 2, 3]
>>> i = iter(l)
>>> i.next()
1
>>> i.next()
2
>>> i.next()
3
>>> i.next()
Traceback (most recent call last):
  File "<ipython-input-6-e590fe0d22f8>", line 1, in <module>
    i.next()
StopIteration

これは、ブロックの最後で呼び出しているため、コードで毎回発生します。そのため、ループが戻ってline空であることがわかる前に例外が発生します。一時的な修正として、次のようなことを行うことができます。ここでは、StopIteration例外をキャッチしてそれを渡します (それは完了したことを示しているため)。

# Your code...
except StopIteration:
    pass
except Exception as e:
  print "Loop exited becuase:"
  print type(e)
  print "at " + line
finally:
  output.close()
于 2013-01-23T00:05:42.823 に答える
0

StopIteration明示的に無視できます:

 try:
     # parse file
     it = iter(cmLines)
     for line in it:
         # here `line = next(it)` might raise StopIteration
 except StopIteration:
     pass
 except Exception as e:
     # handle exception

または、電話line = next(it, None)して確認してくださいNone

問題を分離するために、コードを 2 つの部分に分割できます。

  • 入力をレコードに分割します。
from collections import deque
from itertools import chain, dropwhile, takewhile

def getrecords(lines):
    it = iter(lines)
    headers = "INFERNAL1/a", "HMMER3/f"
    while True:
        it = chain([next(it)], it) # force StopIteration at the end
        it = dropwhile(lambda line: not line.startswith(headers), it)
        record = takewhile(lambda line: not line.starswith("//"), it)
        yield record
        consume(record) # make sure each record is read to the end

def consume(iterable):
    deque(iterable, maxlen=0)
  • 興味のある出力レコード:
from contextlib import closing

with closing(output):
    for record in getrecords(cmLines):
        title, line = next(record, ""), next(record, "")
        if word2(line) in namesList:
           for line in chain([title, line], record):
               output.write(line)
于 2013-01-23T08:04:27.597 に答える
0

1/ 例外処理なし

exception の処理を​​避けるStopIterationには、シーケンスを処理する Pythonic の方法を検討する必要があります (Abarnert が言及したように)。

it = iter(cmLines)
for line in it:
    # do

2/ 捕獲情報

また、正規表現を使用して情報パターンをキャッチすることもできます。最初の行の正確な式を知っていますか。次に、名前をキャッチして、許容される名前のリストと比較します。最後に、次を探しています//。改行を含む正規表現を作成し、グループを使用してチェックしたい名前をキャッチすることができます。

(...)

括弧内の正規表現に一致し、グループの開始と終了を示します。グループの内容は、一致が実行された後に取得でき、後で説明する \number 特殊シーケンスを使用して文字列内で一致させることができます。リテラル '(' または ')' と一致させるには、( または ) を使用するか、文字クラス [(] [)] で囲みます。

Python doc でのグループの正規表現の使用例を次に示します。

>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0)       # The entire match
'Isaac Newton'
>>> m.group(1)       # The first parenthesized subgroup.
'Isaac'
>>> m.group(2)       # The second parenthesized subgroup.
'Newton'
>>> m.group(1, 2)    # Multiple arguments give us a tuple.
('Isaac', 'Newton')

正規表現の詳細。

リンク

Python で例外を発生させるイテレータ next(): https://softwareengineering.stackexchange.com/questions/112463/why-do-iterators-in-python-raise-an-exception

于 2013-01-23T06:21:58.130 に答える
0

私はParser Combinatorsが好きです。より宣言的なスタイルのプログラミングにつながるからです。

たとえば、Parconライブラリの場合:

from string import letters, digits
from parcon import (Word, Except, Exact, OneOrMore,
                    CharNotIn, Literal, End, concat)

alphanum = letters + digits

UntilNewline = Exact(OneOrMore(CharNotIn('\n')) + '\n')[concat]
Heading1 = Word(alphanum + '/')
Heading2 = Word(alphanum + '.')
Name = 'Name' + UntilNewline
Line = Except(UntilNewline, Literal('//'))
Lines = OneOrMore(Line)
Block = Heading1['hleft'] + Heading2['hright'] + Name['name'] + Lines['lines'] + '//'
Blocks = OneOrMore(Block[dict]) + End()

次に、Alex Martelli のBunchクラスを使用します。

class Bunch(object):
    def __init__(self, **kwds):
        self.__dict__.update(kwds)

names = 'John', 'Jane'
for block in Blocks.parse_string(config):
    b = Bunch(**block)
    if b.name in names and b.hleft.upper() in ("INFERNAL1/A', 'HMMER3/F"):
        print ' '.join((b.hleft, b.hright))
        print 'Name', b.name
        print '\n'.join(b.lines)

このファイルを考えると:

Infernal1/a ...
Name John
...
...
...
...
//
SomeHeader/a ...
Name Jane
...
...
...
...
//
HMMER3/f ...
Name Jane
...
...
...
...
//
Infernal1/a ...
Name Billy Bob
...
...
...
...
//

結果は次のとおりです。

Infernal1/a ...
Name John
...
...
...
...
HMMER3/f ...
Name Jane
...
...
...
...
于 2013-01-23T04:46:35.670 に答える