1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

csv.DictReaderオブジェクトを使いまわしてはいけない

Last updated at Posted at 2024-10-24

まとめ

csv.DictReaderオブジェクトを複数回参照してはいけない。
使いまわしたい場合、都度オブジェクトを再生成して参照するべき。

経緯

下記コードの実行時、1度目と2度目で出力結果が変わった。
原因はcsv.DictReaderがイテレータであることにより、1度目のループでイテレータが消費された為であった。

def is_in_targets(data, targets: csv.DictReader):
    if "No." not in targets.fieldnames:
        return False

    # csv.DictReaderをforループにかける
    for row in targets:
        if data["番号"] not in row["No."]:
            continue

        if data["年齢"] in row["Age"]:
            return True
    return False

data = {"番号": "1", "年齢": "12"}
targets = """No.,Age
1,12"""
targets_csv = csv.DictReader(StringIO(targets))
print(is_in_targets(data, targets_csv))    # 出力結果: True
print(is_in_targets(data, targets_csv))    # 出力結果: False

対策

1. リスト変換

-    for row in targets:
+    for row in list(targets):

結果:失敗

list()を実行した場合もイテレータが消費されてしまう

2. オブジェクト再生成

DictReaderオブジェクトを直に渡すのではなく、元のデータを渡した後に関数内でDictReaderオブジェクトを生成する

- def is_in_targets(data, targets: csv.DictReader):
+ def is_in_targets(data, targets_str: str):
+     targets = csv.DictReader(StringIO(targets_str))

結果:成功

data = {"番号": "1", "年齢": "12"}
targets = """No.,Age
1,12"""
print(is_in_targets(data, targets))    # 出力結果:True
print(is_in_targets(data, targets))    # 出力結果:True
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?