csv.Dictreader.fieldnames在Python中是什么类型?

1 投票
2 回答
23 浏览
提问于 2025-04-12 16:44

我正在尝试读取一个csv文件,并从中获取字段名称(也就是csv文件的第一行)。我使用了csv.Dictreader来创建一个读取对象,并通过reader.fieldnames提取了第一行。我知道,对于我将要使用的csv文件,reader.fieldnames会是一个字符串列表。不过,pylance认为reader.fieldnames有可能是None(即没有值),所以它认为reader.fieldnames不能用下标访问。

这是我的代码

import sys
import tabulate
import csv
import typing

def main() -> None:
    menu: list[list[str]] = list()
    
    try:
        file: typing.TextIO
        with open(sys.argv[1]) as file:
            reader: csv.DictReader = csv.DictReader(file)
            headings: list[str] = reader.fieldnames
            row: dict[str,str]
            for row in reader:
                menu.append([row[headings[0]],row[headings[1]],row[headings[2]]])            
    except IOError:
        sys.exit("CSV file does not exist")
    else:
        print(tabulate.tabulate(menu, headers=headings, tablefmt="grid"))

if __name__ == "__main__":
    main()

如果我把headings的类型设为list[str],pylance就会抱怨说

类型为"Sequence[Unknown] | None"的表达式不能赋值给声明的类型"list[str]"

但是,如果我不为headings指定类型,pylance又会在headings[0]时抱怨说

类型为"None"的对象不能用下标访问

我该如何解决这个问题呢?我可以忽略pylance的警告,但我不想这么做,除非真的没有解决办法。

2 个回答

0

fieldnames 可能会是 None,如果 CSV 文件是空的。

你可以通过提供一个默认值来解决这个问题。

headings: list[str] = reader.fieldnames or ["", "", ""]
1

我建议你可以先做一个简单的检查,确认标题(heading)不是空的:

try:
    with open("inpu.csv", newline="") as f:
        reader = csv.DictReader(f, skipinitialspace=True)
        headings = reader.fieldnames
        assert headings is not None
        assert len(headings) == 3

        menu: list[list[str]] = []
        for row in reader:
            menu.append([row[headings[0]], row[headings[1]], row[headings[2]]])
except IOError as e:
    print(f"couldn't open CSV: {e}")
except AssertionError:
    print(
        f"couldn't get fieldnames, check CSV and ensure first line is a properly encoded row"
    )
else:
    print(menu)

如果这个检查失败了,你就知道要去看看CSV文件有没有什么问题。

  • 在检查之前,VSCode会显示标题的类型可能是 Sequence[str] | None,意思是标题可以是字符串的序列,也可能是空的。
  • 在检查之后,类型检查器会明白标题不可能是空的,所以标题的类型必须是 Sequence[str],也就是字符串的序列。

另外,看看Barmar和Mark Tolonen的评论,你可以更简单地通过把CSV文件读取为字符串列表来实现:

reader = csv.reader(f)
menu = list(reader)[1:]

print(menu)
[
    ["foo", "1", "a"],
    ["bar", "2", "b"],
    ["baz", "3", "c"],
]

撰写回答