【问题标题】:Python reading row using list-comprehension (csv and json files) [duplicate]使用列表理解的 Python 读取行(csv 和 json 文件)[重复]
【发布时间】:2021-01-12 04:35:30
【问题描述】:

我对在将文件读取为 csv 或 json 文件时使用列表理解有疑问。 在这第一个代码中,我使用正常的长方法来获取一行的值并将其附加到最后一个空列表中。正如预期的那样,这完全没有问题:

with open("file.csv") as W_F:
    reader = csv.reader(W_F)
    header = next(reader)

    brightness,lons,lats=[], [], []

    for row in reader:
        bright=float(row[2])

        brightness.append(bright)
        lons.append(float(row[0]))
        lats.append(float(row[1]))

在这段代码中,我尝试通过使用列表推导来缩小我的代码,但在这里我遇到了问题。我只得到第一个列表brightness = [float(row[2]) for row in reader] 的值。其他列表打印为空列表(lon = [float(rows[1])for rows in reader]lat = [float(rows[1])for rows in reader])。

with open("file.csv") as W_F:
    reader = csv.reader(W_F)
    header = next(reader)

    brightness = [float(row[2]) for row in reader]
    lon = [float(rows[0])for rows in reader]
    lat = [float(rows[1])for rows in reader]

在这里,我在读取 json 文件时使用了列表推导。我可以毫无问题地获得所有值:

with open("file.json")as f:
    all_eq_data = json.load(f)

all_eq_dicts = all_eq_data['features']

mag = [dicts["properties"]["mag"] for dicts in all_eq_dicts]
lang = [dicts["geometry"]["coordinates"][0] for dicts in all_eq_dicts]
lat = [dicts["geometry"]["coordinates"][1] for dicts in all_eq_dicts]

有人可以向我解释为什么第二个代码中的列表理解不能正常工作吗?为什么在第二个代码中它只将值存储在第一个列表中而不是其他列表中?为什么它在第三个代码中起作用,但在第二个代码中不起作用?如果我做错了,第一个代码和第二个代码有什么区别(注意:第一个和第二个代码使用同一个文件)。

【问题讨论】:

  • 这不是列表推导的好用例。在您的第一个代码中,您仅在一个 for 循环中填充了所有列表。在第二个和第三个代码中,您需要三个列表推导,相当于三个 for 循环。

标签: python json loops csv list-comprehension


【解决方案1】:

在迭代器上进行迭代会为每个项目调用__next__ 方法以获取迭代器中的下一个项目。 for 循环结束的方式是 __next__ 方法抛出 StopIteration 异常,因为它没有更多的项目可以给你。这个机制“烧毁”了迭代器(也就是在迭代结束时不会有更多的“下一个”项目)。

在第二个代码 sn-p 中,您尝试迭代整个迭代器,然后在完成后(当其中没有更多项目时)您尝试在以下列表理解中再次迭代它。

每次对all_eq_data 对象执行for循环时,第三段代码都会创建一个新的迭代器(这是因为它是iterable而不是iterator)(csv.reader 一个迭代器)。

总之-第二个代码在迭代器上运行(第一次使用后会烧坏),第二个代码在迭代器上运行(每次循环时都会返回一个不同的对象)。 有关迭代器和可迭代对象之间区别的更多信息read up

【讨论】:

  • 谢谢 :) 我将阅读更多关于迭代器、可迭代和迭代的内容
【解决方案2】:

你在这里纠缠的事情是由于迭代器方法next().

现在你需要在这里理解一个简单的概念。 for 循环由两部分组成。

1.迭代器

2。来电者

迭代器的目的是创建一个迭代对象,而调用者方法的目的是迭代对象(即开始调用对象)。 现在对于每个迭代器,应该调用一个方法next()。一旦调用该方法,对象的缓冲区将被清空,并且必须在迭代对象之前调用另一个 next() 方法!

下面的例子会更清楚:

这是一个简单的列表

a=[1,2,3,4]
b=iter(a)    // Creates an iterator object in memory

next(b)      // Starts calling the iterator object which only has one iteration till now
>> 1
next(b)
>> 2
next(b)
>> 3

这正是 for 循环所做的,而无需每次显式创建迭代器并调用 next()(默认情况下它会为我们处理!)

for i in range(1,4):  // For loop creates an iterator and calls it consecutively!
    print(i)

>> 1
>> 2
>> 3

在代码块的第二部分,您运行 next(reader),这是迭代器迭代第一行的调用方方法。当您调用brightness = [float(row[2]) for row in reader] 时,第一行的缓冲区将被清空,并且第一行中没有任何东西可以迭代,除非调用next(reader) 方法,该方法将用下一行的数据填充缓冲区!这就是为什么您会为第一个 next(reader) 获得两个对应的空列表

但是,如果您想使用next() 获取项目,我建议您解压缩值:

with open("file.csv") as W_F:
    reader = csv.reader(W_F)
    header = next(reader)

    lon,lat,brightness=header

只需将这些解压缩的值附加到字典或列表中。

希望你能理解!!

【讨论】:

  • 感谢您的帮助
  • 一个“来电者”?这不是标准术语。
  • 是的,不是。在过去的十年中,next() 功能还没有正式的术语接受。但是,它肯定与面向对象的方法调用有关,我认为这对人们很重要,因此他们可以理解其背后的概念。也许这条评论会使“来电者”成为官方术语:-)
猜你喜欢
  • 2015-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 2013-04-03
  • 1970-01-01
  • 1970-01-01
  • 2014-05-03
相关资源
最近更新 更多