0

ユーザーが「いいえ」と入力したときに while を含む最初の for ループが機能する理由と、2 番目のインスタンスが機能しない理由を理解するのに苦労しています。

2 つのループの構造はほぼ同じだと思います。2 番目の出現は、別の関数に分割されただけです。

ユーザーが「いいえ」を入力したときに文字列を削除しないはずです。

これは機能します。ユーザーが「いいえ」を入力すると、何も削除されません。

def remove():
    f = open('codilist.txt')
    coname = raw_input('What company do you want to remove? ') # company name
    tmpfile = open('codilist.tmp', 'w')
    for line in f:
        if coname.upper() in line:
            while True:
                answer = raw_input('Are you sure you want to remove company?\nyes or no?')
                if answer == 'yes':
                    print line.upper() + '...has been removed.'
                    break                
                elif answer == 'no':
                    f.close()
                    tmpfile.close()
                    return
                else:
                    print 'Please choose yes or no.'                    
        else:
            tmpfile.write(line)
    f.close()
    tmpfile.close()
    os.rename('codilist.tmp', 'codilist.txt')

これは機能しません。ユーザーが「いいえ」と入力すると、とにかく文字列が削除されます。

def find_and_remove(f,coname,tmpfile):
    for line in f:
        if coname.upper() in line:
            while True:
                answer = raw_input('Are you sure you want to remove company?\nyes or no?')
                if answer == 'yes':
                    print line.upper() + '...has been removed.'
                    break               
                elif answer == 'no':
                    f.close()
                    tmpfile.close()
                    return
                else:
                    print 'Please choose yes or no.'                   
        else:
            tmpfile.write(line)

def remove():
    f = open('codilist.txt')
    coname = raw_input('What company do you want to remove? ') # company name
    tmpfile = open('codilist.tmp', 'w')
    find_and_remove(f,coname,tmpfile)
    f.close()
    tmpfile.close()
    os.rename('codilist.tmp', 'codilist.txt')
4

5 に答える 5

3

より良いコーディング スタイルを示すために、以下のスクリプトを自由に書き直しました。

def get_user_in(message, valid_responses):
    while True:
        user_in = raw_input(message)
        if user_in in valid_responses:
            return user_in
        else:
            print "Please choose from: {0} or {1}".format(*valid_responses)

def find_and_remove(co_name, infile, outfile):
    pattern = co_name.upper()
    for line in infile:
        if pattern in line.upper():
            print line
            answer = get_user_in("Remove this line? ", ("yes", "no"))
            if answer == "no":
                outfile.write(line)
        else:
            outfile.write(line)

def remove(filename):
    outFilename = filename + '.tmp'
    with open(filename, 'r') as infile, open(outFilename, 'w') as tmpfile:
        co_name = raw_input('What company do you want to remove? ')
        find_and_remove(co_name, infile, tmpfile)
    os.rename(outFilename, filename)
于 2012-07-08T21:56:24.173 に答える
2

この全体をやり直す方法の良い例については、Joel's wiki answerを参照してください。

しかし、エラーの修正に関しては...

あなたの2つの例の大きな違いが何であるかにようやく気づきました。を実行するときと関係がありますrename

最初の例では、ユーザーが「いいえ」と言ったときに、関数全体から戻ると、os.renameすべての出来事が妨げられます。その結果、まったく変更されていない元の .txt ファイルが表示されます。

2 番目の例では、ユーザーが「いいえ」と言った場合、サブ関数からメイン関数に戻りますが、os.rename何が起こってもかまいません。つまり、彼らがいいえと言った場合、それ以上行を書き込むことはありませんが、まだ半分処理された tmp ファイルをコピーします。

正直なところ、全体を書き直す必要があると思いますが、現在のコードを簡単に微調整するとfind_and_remove、プロセスが成功したかどうかをブール値で返すことができます。

def find_and_remove(f,coname,tmpfile):
    ...             
                elif answer == 'no':
                    return False
    return True

def remove():
    ...
    success = find_and_remove(f,coname,tmpfile)
    f.close()
    tmpfile.close()
    if success:
        os.rename('codilist.tmp', 'codilist.txt')

正直なところ、withファイルをいつ閉じるかという一連の条件を混同する必要がないように、ファイルを開いたり閉じたりするためにコンテキストを使用することを検討する必要があります。2 つの異なる関数でそれらを閉じています。

withステートメント_

with open('infile.txt') as inFile, open('outfile.txt', 'w') as outFile:
    for line in inFile:
        outFile.write(line)

withブロックが終了すると、ファイルを閉じます。

于 2012-07-08T21:52:53.490 に答える
1

return問題は「no」句にあるように私には見えます。これは、メソッドが実行される前に関数を終了するtmpfile.write(line)ため、文字列が削除されたように見えるのは理にかなっています。私が理解していないのは、なぜそれが最初の関数で機能するのかということです。

于 2012-07-08T21:37:35.747 に答える
0

find_and_remove2番目のケースでは、ユーザーが入力したときにのみ戻りますno。最初のケースでは、関数全体から戻ります。

于 2012-07-08T21:34:49.923 に答える
0

私はジョエルと同じ考えを持っていましたが、少し遅くなりました...関係なく、これが興味深いものになることを願っています:

COMPANY_FILE = 'codilist.txt'

def load_companies():
    with open(COMPANY_FILE) as inf:
        return filter(None, (line.strip() for line in inf))

def save_companies(companies):
    with open(COMPANY_FILE, 'w') as outf:
        outf.write('\n'.join(companies))

def get_option(prompt, options):
    options = [opt.strip().lower() for opt in options]
    prompt = "{}? [{}]".format(prompt, '/'.join(options))
    options = set(options)
    while True:
        res = raw_input(prompt).strip().lower()
        if res in options:
            return res

def remove_company(remove, companies):
    ask = lambda c: get_option('Remove company {}'.format(c), ['yes', 'no'])
    return [co for co in companies if remove not in co or ask(co)=='no']

def main():
    companies = load_companies()
    co_len = len(companies)

    remove = raw_input('Name of company to remove?').strip()
    companies = remove_company(remove, companies)

    if len(companies) < co_len:
        save_companies(companies)

if __name__=="__main__":
    main()
于 2012-07-08T22:04:02.360 に答える