【问题标题】:Why won't my class that returns a list iterate?为什么我的返回列表的类不会迭代?
【发布时间】:2012-12-30 01:34:48
【问题描述】:

这是我的代码,我用它打开一个 Excel 表,然后将每一行作为字符串列表返回(其中每个单元格都是一个字符串)。该类返回一个列表,该列表填充的列表与文件中的行数一样多。所以 50 行将返回 50 个列表。

from xlrd import open_workbook

class ExcelReadLines(object):

    def __init__(self,path_to_file):
        '''Accepts the Excel File'''
        self.path_to_file = path_to_file
        self.__work__()


    def __work__(self):
        self.full_file_as_read_lines = []
        self.book = open_workbook(self.path_to_file)
        self.sheet = self.book.sheet_by_index(0)

        for row_index in range(self.sheet.nrows):
            single_read_lines = []
            for col_index in range(self.sheet.ncols):
                cell_value_as_string = str(self.sheet.cell(row_index,col_index).value)
                cell_value_stripped = cell_value_as_string.strip('u')
                single_read_lines.append(cell_value_stripped)
            self.full_file_as_read_lines.append(single_read_lines)

        return self.full_file_as_read_lines

但是当我跑步时:

for x in ExcelReader('excel_sheet'): print x

我收到错误消息:

class is not iterable

【问题讨论】:

    标签: python class python-2.7 iterator


    【解决方案1】:

    为了让一个类可以迭代,它需要有一个__iter__ 方法。

    考虑:

    class Foo(object):
        def __init__(self,lst):
            self.lst = lst
        def __iter__(self):
            return iter(self.lst)
    

    示例:

    >>> class Foo(object):
    ...     def __init__(self,lst):
    ...         self.lst = lst
    ...     def __iter__(self):
    ...         return iter(self.lst)
    ... 
    >>> Foo([1,2,3])
    <__main__.Foo object at 0xe9890>
    >>> for x in Foo([1,2,3]): print x
    ... 
    1
    2
    3
    

    您的示例似乎作为生成器会好一点——我不太明白这里需要什么类:

    def excel_reader(path_to_file):
        book = open_workbook(path_to_file)
        sheet = book.sheet_by_index(0)
    
        for row_index in range(sheet.nrows):
            single_read_lines = []
            for col_index in range(sheet.ncols):
                cell_value_as_string = str(self.sheet.cell(row_index,col_index).value)
                cell_value_stripped = cell_value_as_string.strip('u')
                single_read_lines.append(cell_value_stripped)
            yield single_read_lines
    

    【讨论】:

    • 我环顾四周,这似乎是共识。但我不明白如何使用它来返回列表列表。
    【解决方案2】:

    您应该考虑实现 Python 的 special iterator methods

    另外,请注意,您不应将方法命名为 __work__,因为它使用魔术方法语法,但实际上并不是真正的魔术方法。

    【讨论】:

      【解决方案3】:

      这里有一些问题。

      1. 您的代码没有返回任何内容。您调用 __work__ 但不返回值。

      2. 即使有,也无济于事,因为从 __init__ 返回的东西不会使对象成为那个东西。

      3. 无论如何,您不希望您的对象成为一个列表,您只想对其进行迭代。

      有关如何在 Python 中编写迭代器的简单示例,请参阅 this question

      此外,您不应在代码中使用像__work__ 这样的双下划线三明治名称。按照惯例,这种名称是为 Python 内部使用而保留的。

      【讨论】:

      • 我不明白你的第一点。我相信它确实返回了一个值。 init 调用 work 方法,work 方法返回一个列表。另外,我想要一个列表列表,这样我可以根据算法对每个列表进行排序,并将每个列表放入一个桶或另一个桶中。
      • @user1367204 -- 要从函数返回值,您需要 return 语句。而且,python 不尊重来自 __init__ 的值 returned。
      【解决方案4】:

      除非我弄错了,否则你真正追求的是

      def first_sheet(fname):
          wb = xlrd.open_workbook(fname)
          ws = wb.sheet_by_index(0)
          for i in xrange(ws.nrows):
              yield ws.row_values(i) # maybe strip 'u''s - but that looks a bit sus... (probably something to do with your `str`)
      
      list_of_rows = list(first_sheet('somefile.xls'))
      

      然后根据需要使用zip 进行任何换位...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多