【问题标题】:Why is my attempt to unpack a map resulting in `TypeError: 'int' object is not iterable`为什么我尝试解压地图会导致“TypeError:'int' object is not iterable”
【发布时间】:2020-03-05 15:00:52
【问题描述】:

我知道TypeError: 'int' object is not iterable 发生在我们尝试迭代不可迭代的东西时。例如,

for x in 4:
    pass

m = map(str, 99)

在我的例子中,我构建了一个地图,即使出现问题,它也不会失败,直到以后。像下面这行代码执行得很好

m = map(foo, [1, 2, 3])

问题在于我的函数foo。后来,当我尝试解压映射迭代器时,例如写list(m)foo 引发TypeError,我就是不知道为什么。

import itertools    

def contains_iter(cont):
    """
    returns true if container is an iterator
                 or
                 if container is not an iterator
                 but container contains an iterator
                 or
                 if container is not an iterator
                 but container contains a container
                 which contains an iterator.
                 etc...
    """
    range_type = type(range(1))
    if hasattr(cont, "__next__") or isinstance(cont, range_type):
        return True
    try:
        for elem in cont:
            if elem == cont:
                # string "a" in "a"
                break
            if contains_iter(elem):
                return True
        r = False
    except TypeError:
        # object is not iterable
        r = False
    finally:
        pass
    return r

def deiter(it):
    status = contains_iter(it)
    if status:
        assert(hasattr(it, "__iter__"))
        mahp = map(deiter, it)
        tup = tuple(mahp)
        return tup
    return it


def print_io(inny):
    def outty(*args):
        args = deiter(args)
        try:
            output = inny(*args)
        except BaseException as exc:
            output = str(type(exc)) + str(exc)
        output = deiter(output)
        call_sig = "flatten" + str(args)
        output = "OUTPUT:  " + str(output)
        print(40*"#", call_sig, output, 40*"#", sep="\n")
        return
    return outty

class FlatClass:
    def __call__(self, *args):
        try:
            if len(args) <= 1:
                try:
                    r = iter(args[0])
                except BaseException:
                    r = args[0]
                    # if len(args) == 0
                    # `args[0]` raises
                    # exception
            else:
                args = map(self, args)
                r = itertools.chain(*args)
        except IndexError:
            r = tuple() # empty tuple
        finally:
            pass
        return r

flatten = print_io(FlatClass())

flatten(1, [2])

【问题讨论】:

  • 跟踪的确切错误是什么?
  • 这段代码非常复杂,不清楚其中的目标是什么。你想做什么? (如果这是不再执行您最初尝试执行的操作的简化代码,那么您似乎可以进一步简化它,同时仍然重现错误。)
  • 另外,finally: pass 完全没有意义。
  • 顺便说一句,你的函数不正确。 range 对象不是迭代器,要检查某物是否是迭代器,您需要检查 __next____iter__ 是否同时存在,并且有很多奇怪的复杂的事情正在发生......比如,什么在世界是if elem == cont:应该在做什么?
  • @juanpa.arrivillaga elem == cont 的目的是检查可迭代对象是否为字符串。 iter(iter(iter(iter(iter(iter('a')))))) == iter('a')。您不想在hasattr(obj, '__iter__') 的基础上进行递归,因为这将导致字符串无限循环。

标签: python python-3.x iterator


【解决方案1】:

你有一个 itertools.chain 调用试图链接不可迭代的东西:

else:
    args = map(self, args)
    r = itertools.chain(*args)

其中一些参数是整数。这在创建链迭代器时不会检测到,只有在您最终尝试对其进行迭代时才会检测到。

不知道这段代码的目标是什么,我们不能说如何修复它。这段代码还有很多其他部分是可疑的(范围不是迭代器)、无目的的(finally: pass)或不必要的复杂(range_type = type(range(1)) 只是设置了range_type = range),而且几乎可以肯定还有更多的错误,但是这是导致直接问题的原因。

【讨论】:

  • finally: pass 的目的是设置一个 try-catch 块(良好做法),以便将来有人可以添加 finallyexcept 子句。目前,没有捕获到异常,finally 什么也不做,但那是因为代码处于开发的早期阶段。最终,可能确实想在finally 子句中添加一些代码。
  • @ToothpickAnemone:但是发布的代码中的每个finally: pass 都附加到已经有excepttry,因此try 不需要finally有效。此外,任何人都可以在没有此设置的情况下轻松添加 try-except ;它对误导和迷惑读者的作用比实际上使任何事情变得更容易的作用更大。
猜你喜欢
  • 1970-01-01
  • 2018-12-10
  • 1970-01-01
  • 2019-09-22
  • 1970-01-01
  • 1970-01-01
  • 2018-06-29
  • 1970-01-01
  • 2019-04-12
相关资源
最近更新 更多