csv.Dictreader.fieldnames在Python中是什么类型?
我正在尝试读取一个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"],
]