質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.77%

pythonのargparseを用いたファイル読み込みの不具合

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,255

M.Temma

score 7

前提・実現したいこと

pythonでオプション("-3"や"-6")をつけて場合分けをし、さらに引数としてファイルを読み込みファイルの中身について操作を行うプログラムを作ろうとしています。
具体的に書くと、ターミナルで
$ python PracticeD-3.py test.fa
として実行すると、ファイル"test.fa"を読み込み、関数"frame1"のみを実行する
$ python PracticeD-3.py -3 test.fa
として実行すると、ファイル"test.fa"を読み込み、関数"frame1"と"frame3"を順番に実行する
$ python PracticeD-3.py -6 test.fa
として実行すると、ファイル"test.fa"を読み込み、関数"frame1"と"frame3"と"frame6"を順番に実行する
というようなプログラムを作ろうとしています。

しかし、実装すると下記のような実行となりうまくいきません。

なお、ファイル"test.fa"の中身は次の通りです。

>sequence1
ccg agc aga gct ttc tgg aga gag gaa gag gaa gag gaa gtg gga ggc ggg ccc tag

発生している問題・エラーメッセージ

オプション無しの場合は、

$ python PracticeD-3.py test.fa
として実行すると、
>sequence1
ccg agc aga gct ttc tgg aga gag gaa gag gaa gag gaa gtg gga ggc ggg ccc tag
frame1

と出力され問題ないのですが、
"-3"のオプションをつけて、

$ python PracticeD-3.py -3 test.fa
として実行すると、
>sequence1
ccg agc aga gct ttc tgg aga gag gaa gag gaa gag gaa gtg gga ggc ggg ccc tag
frame1
frame3

と出力され、関数"frame1"が実行された後、ファイルの中身がうまく読み込めないか、なくなってしまっているのです。
オプション"-6"の時も同様で、

python PracticeD-3.py -6 test.fa
>sequence1
ccg agc aga gct ttc tgg aga gag gaa gag gaa gag gaa gtg gga ggc ggg ccc tag
frame1
frame3
frame6

となってしまいます。
argparseの仕様がよくわかっていないことが大きいと思いますが、どうすれば

$ python PracticeD-3.py -3 test.fa
>sequence1
ccg agc aga gct ttc tgg aga gag gaa gag gaa gag gaa gtg gga ggc ggg ccc tag
frame1
>sequence1
ccg agc aga gct ttc tgg aga gag gaa gag gaa gag gaa gtg gga ggc ggg ccc tag
frame3

といったように、関数ごとにうまく実行できるでしょうか。
ご助言よろしくお願いします。

該当のソースコード

#!/usr/bin/env python
# coding: utf-8

import sys
import argparse


def main():
    parser = argparse.ArgumentParser(description='Process options')
    group = parser.add_mutually_exclusive_group()
    group.add_argument('-3', dest='frame3', action='store_true',
                       default=False, help='recognize -3')
    group.add_argument('-6', dest='frame6', action='store_true',
                       default=False, help='recognize -6')
    parser.add_argument('file', type=file)
    args = parser.parse_args()
    if args.frame3:
        test_file1 = args.file
        test_file2 = args.file
        frame1(test_file1)
        frame3(test_file2)
    elif args.frame6:
        test_file1 = args.file
        test_file2 = args.file
        test_file3 = args.file
        frame1(test_file1)
        frame3(test_file2)
        frame6(test_file3)
    else:
        frame1(args.file)


def frame1(f):
    for i in f:
        print i,
    print "frame1"


def frame3(f):
    for i in f:
        print i
    print "frame3"


def frame6(f):
    for i in f:
        print i
    print "frame6"


if __name__ == "__main__":
    main()

補足情報(言語/FW/ツール等のバージョンなど)

テキストエディタ:atom
実行環境:python2.7.10

なお、質問のために関数は単純なものにしてあります。
あくまで問題解決のための即席関数です。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

全ての関数で同じファイルオブジェクトを参照しています。
このため、frame1(f)でファイルを読み終わった段階でそのファイルオブジェクトはファイルの終端を参照しています。
このためframe3, frame6では読むものがもうないので何も起きていないように見えます。

つまりこう書いているのと同じことが起きています。

def frame1(f):
    for i in f:
        print i,
    print "frame1"
    for i in f:
        print i
    print "frame3"

今回で言えば各関数の先頭でファイルオブジェクトを先頭に戻せば元の位置に戻ります。

def frame1(f):
    f.seek(0)   #これを追加
    for i in f:
        print i,
    print "frame1"


frame3,frame6にも同様にf.seek(0)を入れてください。

ただし今回のプログラムでは影響は出ませんが、関数間が関係しあうプログラムだと他の関数の動作に影響がでますのでその点は注意してください。

例えば

def frame1(f):
    f.seek(0)
    print "1 :", f.readline()
    frame4(f)
    print "1 :", f.readline()

def frame4(f):
    f.seek(0)
    print "4 :", f.readline()


こういう処理だった場合にはframe4の操作がframe1の操作に影響を及ぼすという意味です


余談ですが、python2系(2.7.5以降だったかな)を使うときは先頭で、3系互換のprint_functionを強制するようにしておいた方が良いでしょう。

#!/usr/bin/env python
# coding: utf-8
from __future__ import print_function
import sys
import argparse

# print "aaa"  # エラーとなる
print("aaa")  # こっちだと print関数に関しては3系にすぐ適用できる

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/31 11:57

    解決しました!
    どうもありがとうございますm(__)m

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る