【问题标题】:Making objects iterable?使对象可迭代?
【发布时间】:2018-01-23 19:08:09
【问题描述】:

我正在尝试遍历列表列表中的每一行,将每一行中的一个元素附加到一个新列表中,然后在新列表中找到唯一的元素。

我知道我可以使用 for 循环轻松完成此操作。我正在尝试不同的路线,因为我想了解更多关于类和函数的信息。

这是列表列表的示例。第一行是表头:

legislators = [
 ['last_name', 'first_name', 'birthday', 'gender', 'type', 'state', 'party'],
 ['Bassett', 'Richard', '1745-04-02', 'M', 'sen', 'DE', 'Anti-Administration'],
 ['Bland', 'Theodorick', '1742-03-21', '', 'rep', 'VA', ''],
 ['Burke', 'Aedanus', '1743-06-16', '', 'rep', 'SC', ''],
 ['Carroll', 'Daniel', '1730-07-22', 'M', 'rep', 'MD', ''],
 ['Clymer', 'George', '1739-03-16', 'M', 'rep', 'PA', ''],
 ['Contee', 'Benjamin', '', 'M', 'rep', 'MD', ''],...]

这是我的代码:

import csv
f = open("legislators.csv")
csvreader = csv.reader(f)
legislators = list(csvreader)

class Dataset:
    def __init__(self, data):
        self.header = data[0] #Isolate header from CSV file
        self.data = data[1:] #Subset CSV data to remove header

legislators_dataset = Dataset(legislators)

def the_set_maker(dataset):
    gender = []
    for each in dataset:
        gender.append(each[3])
    return set(gender)

t=the_set_maker(legislators_dataset)
print(t)

我收到以下错误:

TypeErrorTraceback (most recent call last)
<ipython-input-1-d65cb459931b> in <module>()
     20     return set(gender)
     21
---> 22 t=the_set_maker(legislators_dataset)
     23 print(t)

<ipython-input-1-d65cb459931b> in the_set_maker(dataset)
     16 def the_set_maker(dataset):
     17     gender = []
---> 18     for each in dataset:
     19         gender.append(each[3])
     20     return set(gender)

TypeError: 'Dataset' object is not iterable

我认为答案是尝试在我的 Dataset 类中使用 def __iter__(self) 创建一个方法,但我无法让它工作。这是正确的轨道吗?如果没有,有什么更好的?

【问题讨论】:

  • 要使一个对象iterable,它需要实现__iter__,它必须返回一个iterator,即实现@987654327的对象@ __next__。迭代器 __iter__ 方法应该简单地返回 self
  • @juanpa.arrivillaga 谢谢。我将研究下一个。你能演示如何在我的代码中使用 nextiter 吗?
  • 我不相信这是一个副本。您用“什么是可迭代的”回答了“我如何使我的类可迭代”,这需要至少一两个逻辑跳转来实现。我已经重新打开了。
  • 您应该能够通过将您的 iter 方法定义为 return iter(self.data) 来获得您正在寻找的行为。或者,看看用你的 CSV 文件(或列表对象)制作一个 Pandas DataFrame,然后按名称引用该列
  • 顺便说一句,你可以做self.header, *self.data = data...

标签: python class iterable


【解决方案1】:

你需要改变一点

class Dataset:
    i = 0

    def __init__(self, data):
        self.header = data[0] #Isolate header from CSV file
        self.data = data[1:] #Subset CSV data to remove header

    def __iter__(self):
        return self
    def __next__(self):
        return self.next()

    def next(self):
        if self.i < len(self.data):
            self.i += 1
            return self.data[self.i-1]
        else:
            raise StopIteration()

【讨论】:

  • 这个实现错误,你不需要.next__next__,前者是Python 2,后者是Python 3,不要混用他们。
  • 另外,这使得Dataset 成为一个迭代器,这几乎肯定不是你想要的。
  • 没关系,我想,如果您想编写可在 Python 2/3 上运行的代码,但这里的主要问题是您已将 Dataset 设为 迭代器 i>,而不仅仅是 iterable,这不是一个好习惯。考虑所有内置容器类型,listtupleset 等 - 这些从 iter 返回专门的迭代器对象,而不是它们本身。 迭代器返回自己。
  • 另外,您已将i 设为类变量,然后用实例变量隐藏它,这并不是您真正想要的,并且可能导致细微的错误...
  • @Yuriy Arhipov 我感谢您的帮助 - 就像我选择的答案一样,它有点超出我的能力,但这很好。
【解决方案2】:

根据the documentation for __iter__

此方法应返回一个新的迭代器对象,该对象可以迭代容器中的所有对象。

您可以尝试以下类定义:

class Dataset:
    def __init__(self, data):
        self.header = data[0] #Isolate header from CSV file
        self.data = data[1:] #Subset CSV data to remove header

    def __iter__(self):
        return iter(self.data)

如果您愿意尝试新的选择,请考虑使用 Pandas:

import pandas as pd
df = pd.read_csv('legislators.csv')
t=df['gender']

或者,如果您真的想自己阅读 CSV,

df = pd.DataFrame(legislators[1:], columns=legislators[0])

【讨论】:

  • pandas 似乎无关紧要。无论如何,csv 模块很好......
  • 没错,这与学习如何使对象可迭代无关。但是,在给出的特定情况下,他提到希望从每一行中获取特定元素,在这种情况下,numpy 或(因为我们已经标记了列)pandas 非常适合此目的
  • ... 标准库 csv 也是如此,它不需要重重的 numpy/pandas 依赖,只是从 csv 文件中的列中获取数据。
  • 我能够让代码工作 - 感谢大家的帮助和其他想法,尤其是 DataFrame。如您所见,我对这一切都很陌生,所以我非常感谢您的支持。
【解决方案3】:

正如您所提到的,您需要在class Dataset 中实现__iter__。请注意,这实际上是引发错误的 set(...) 调用,因为它遍历您的类以枚举集合元素。

幸运的是,您的 set 元素可能只是 Dataset.data,这使得编写 Dataset.__iter__ 变得容易。

class Dataset(object):
    ...

    def __iter__(self):
        return iter(self)

不过,我要指出的是,您的 the_set_maker 函数似乎有点过于专业化,无法成为顶级函数。它也有点微不足道,因为它实际上是set([el[3] for el in container])。我也会把它放在Dataset 中。

class Dataset(object):
    ...

    def to_set(self):
        return set([el[3] for el in self.data])
        # Note that this throws away your header!

【讨论】:

  • 谢谢你。我同意这个函数是微不足道的——我正在尝试使用类和函数,即使它们是微不足道的,这样我就可以更熟悉它们,所以我很欣赏你的例子,我可以将函数合并到类中!跨度>
猜你喜欢
  • 2019-06-03
  • 1970-01-01
  • 1970-01-01
  • 2015-11-28
  • 2020-02-12
  • 2012-08-10
  • 2019-12-03
  • 2019-11-12
  • 2017-01-05
相关资源
最近更新 更多