【问题标题】:how to handle "Too many values to unpack"如何处理“解包的值太多”
【发布时间】:2015-07-22 02:32:11
【问题描述】:

我已经检查了一些想法和原因,下面针对这个问题进行了调查...... "Too many values to unpack" Exception (Stefano Borini 的解释)

但在这里我将列表作为理解列表进行迭代并将结果移动到列表中......! 所以输入的数量读取输出变量的数量,即tempList...

那么,这个过程有什么问题呢?!

def DoProcess(self, myList):
    tempList = []
    tempList = [[x,y,False] for [x,y] in myList]
    return tempList

编辑 1:myList 是一个列表列表,就像 [[x1, y1], [x2, y2], [x3, y3], [x4 y4]]

class Agent(object):
    def __init__(self, point = None):
        self.locationX = point.x
        self.locationY = point.y

    def __iter__(self):
        return self

    def __next__(self):
        return [self.locationX, self.locationY]

    def __getItem__(self):
        return [self.locationX, self.locationY]

    def GenerateAgents(self, numberOfAgents):
        agentList = []
        while len(agentList) < numberOfAgents:

            point = Point.Point()
            point.x = random.randint(0, 99)
            point.y = random.randint(0, 99)

            agent = Agent(point)
            agentList.append(agent)
        return agentList

    def DoProcess(self, myList):
        tempList = []
        tempList = [[x[0],x[1],False] for x in myList]
        return myList

每个Point 有两个属性locationXlocationY...

【问题讨论】:

  • myList的结构是什么?
  • myList 是否包含 2 个元素元组的列表?如果它们每个都有超过 2 个元素,那么你会遇到麻烦。
  • 请检查应用的编辑...
  • @Ordenador:那么您的输入实际上并不符合您的规范。你能分享一下myList到底是什么吗?
  • @Ordenador 您应该准确打印列表中的内容,显然您有一个原子对象列表。或者你有一个混合对象的列表。

标签: python


【解决方案1】:

可能是这样的:

def DoProcess(self, myList):
    tempList = [[x[0],x[1],False] for x in myList]
    return tempList

【讨论】:

  • 谢谢...但即使实现了__getItem__()__iter__() 函数,Object does not support indexing 也会出现异常...
  • @Ordenador 这意味着您的列表中有不可迭代的对象。这意味着不能拆成 2 件商品
  • @LoïcFaure-Lacroix:但我应该能够...我已经实现了__getItem__() 方法...我说的对吗?!...
【解决方案2】:

您对Agent 的实现存在严重缺陷;你创建了一个 infinite 生成器:

def __iter__(self):
    return self

def __next__(self):
    return [self.locationX, self.locationY]

这将永远产生具有两个值的列表。尝试在元组分配中使用此对象将产生至少 3 个这样的值(xy 目标为 2 个,另外还有一个用于让 Python 知道要解包的值比请求的要多)。 Python 所做的是每次需要序列中的另一个值时调用__next__,而您的代码每次只返回[x, y]。永远永远,直到永远。

__iter__ 方法应该返回对两个值的实际迭代:

def __iter__(self):
    for value in (self.locationX, self.locationY):
        yield value

甚至只是

def __iter__(self):
    yield self.locationX
    yield self.locationY

完全放弃__next__。上面的生成器将产生两个值,然后正确地引发StopIteration,并使用元组赋值。

__getitem__ 方法拼写为全部小写,并采用索引参数:

def __getitem__(self, index):
    return (self.locationX, self.locationY)[index]

现在0 映射到locationX1locationY

使用这些更改重写您的代码:

class Agent(object):
    def __init__(self, point):
        self.locationX = point.x
        self.locationY = point.y

    def __iter__(self):
        yield self.locationX
        yield self.locationY

    def __getitem__(self, index):
        return (self.locationX, self.locationY)[index]

    def GenerateAgents(self, numberOfAgents):
        agentList = []
        for _ in range(numberOfAgents):
            point = Point.Point()
            point.x = random.randint(0, 99)
            point.y = random.randint(0, 99)

            agent = Agent(point)
            agentList.append(agent)
        return agentList

    def DoProcess(self, myList):
        return [[x, y, False] for x, y in myList]

【讨论】:

  • 对于“2个或更多”,他不能解压到x,y,*_吗?
  • 非常感谢您的解释......但即使我已经实现了__getItem__() 方法,我也无法通过[[elem[0], elem[1], False] for elem in myList] 进行迭代,因为Object does not support indexing
  • @Ordenador:你在那里拼错了方法名称; i小写
  • @Ordenador:您对__getitem__ 的实现存在很大缺陷;您不返回列表,而是返回给定索引处的项目,但您没有指定receive给定索引的参数。
  • @MartijnPieters:请告诉我如何改写__getitem__()?...
【解决方案3】:

您的列表需要包含长度为 2 的嵌套迭代,xy 已解包。

【讨论】:

    【解决方案4】:

    你可以这样做

    def DoProcess(self, myList):
        return [sublist + [False] for sublist in myList]
    

    关于为什么这不起作用有多种选择:

    1. myList 的某个地方,您有少于两个元素的子列表(或更一般地说,长度不是2 的子列表)。你可以找到他们

      print [sublist for sublist in myList if len(sublist) != 2]
      
    2. myList 中有一些不是列表的元素。你可以找到他们

      print [element for element in myList if not isinstance(element, list)]
      

    将它们组合在一起

    print [element for element in myList if not isinstance(element, list) or len(element) != 2]
    

    【讨论】:

    • 这不应该工作......因为[False]类型与sublist类型不兼容......
    【解决方案5】:

    创建 getitem 方法的正确方法是这样编写:

    def __getitem__(self, index):
        if index == 0:
           return self.locationX
        if index == 1:
           return self.locationY
        raise IndexError()
    

    请注意,它有一个作为参数传递的索引,它写成__getitem__ 而不是__getItem__。如果没有索引错误,python 似乎会尝试解压缩尽可能多的值,直到 getitem 引发索引错误。

    并不是说您可以简化代码并为索引 2 添加一个子句并返回 False。

    老实说,我看不出在这里覆盖getitem 的意义。写出来会更容易理解。

    tempList = [[x.locationX,x.locationY,False] for x in myList]
    

    这个也不需要写了:

    tempList = []
    tempList = [...]
    

    创建一个空列表来替换它是没有意义的。

    这是一个重新设计的代码示例。请注意,我将方法GenerateDoProcess 更改为staticmethod。它们可以设为静态,因为它们实际上不需要任何实例来工作。您可以使用 Agent 类直接调用它们。我删除了迭代器 getitem ,因为它们在这里并不是必需的。如果在其他地方使用它们可能会造成麻烦。

    问题是,在这种情况下,从代理中解压缩值似乎很奇怪。如果我能看到这样的代码......我不会理解迭代器或__getitem__ 的需求。 agent[0] 是它的X 位置和agent[1],它的Y 位置并不明显。 Python 命名属性是有原因的。如果您不使用它们,那么您可以简单地将代理存储在列表中而不是类中。这正是DoProcess 方法的作用。

    class Agent(object):
    
        def __init__(self, point):
            self.locationX = point.x
            self.locationY = point.y
    
        @staticmethod
        def GenerateAgents(numberOfAgents):
            agentList = []
    
            for i in range(numberOfAgents):
                point = Point.Point()
                point.x = random.randint(0, 99)
                point.y = random.randint(0, 99)
    
                agent = Agent(point)
                agentList.append(agent)
    
            return agentList
    
        @staticmethod
        def DoProcess(myList):
            return [
                [obj.locationX, obj.locationY, False]
                for obj in myList
            ]
    

    【讨论】:

    • @Ordenador 谢谢,我重写了你的课程以简化它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    • 2020-01-15
    相关资源
    最近更新 更多