代码之家  ›  专栏  ›  技术社区  ›  Evandro Coan

如何将对象作为for循环中的元组进行解包?

  •  2
  • Evandro Coan  · 技术社区  · 6 年前

    class Test(object):
    
        def __init__(self, arg):
            self.arg1 = arg + 1
            self.arg2 = arg + 2
            self.arg3 = arg + 3
    
        def __iter__(self):
            return self
    
        def __next__(self):
            yield self.arg1, self.arg2, self.arg3
    
    
    test_list = [Test(0), Test(1), Test(2)]
    
    for arg1, arg2, arg3 in test_list:
        print('arg1', arg1, 'arg2', arg2, 'arg3', arg3)
    

    但当我试着跑的时候,python说:

    Traceback (most recent call last):
      File "test.py", line 20, in <module>
        for arg1, arg2, arg3 in test_list:
    ValueError: too many values to unpack (expected 3)
    

    我可以手动打开包装:

    class Test(object):
    
        def __init__(self, arg):
            self.arg1 = arg + 1
            self.arg2 = arg + 2
            self.arg3 = arg + 3
    
    test_list = [Test(0), Test(1), Test(2)]
    
    for test in test_list:
        arg1, arg2, arg3 = test.arg1, test.arg2, test.arg3
        print('arg1', arg1, 'arg2', arg2, 'arg3', arg3)
    

    我们如何在python列表中解压对象,而不象解决方法所演示的那样显式地进行呢?对于最后一个示例,结果如下:

    arg1 1 arg2 2 arg3 3
    arg1 2 arg2 3 arg3 4
    arg1 3 arg2 4 arg3 5
    
    4 回复  |  直到 6 年前
        1
  •  7
  •   Ajax1234    6 年前

    你很接近,但是,你需要 yield 中的值 __iter__ __next__

    class Test:
      def __init__(self, arg):
        self.arg1 = arg + 1
        self.arg2 = arg + 2
        self.arg3 = arg + 3
      def __iter__(self):
        yield from [self.arg1, self.arg2, self.arg3]
    
    for a, b, c in [Test(0), Test(1), Test(2)]:
      pass
    

    yield self.arg1, self.arg2, self.arg3 会给一个 tuple 结果 (1, 2, 3)

    for [(a, b, c)] in [Test(0), Test(1), Test(2)]:
      pass
    

    因此,为了避免循环中额外的解包,您必须通过在属性上循环并一次生成每个属性来创建一个生成值流。

        2
  •  6
  •   Aran-Fey Kevin    6 年前

    问题是你的 __next__ Test 类iterable,但它不会迭代您认为它是如何执行的:

    >>> itr = iter(Test(0))
    >>> next(itr)
    <generator object Test.__next__ at 0x7ff609ade9a8>
    >>> next(itr)
    <generator object Test.__next__ at 0x7ff609ade930>
    >>> next(itr)
    <generator object Test.__next__ at 0x7ff609ade9a8>
    

    而不是屈服于 (self.arg1, self.arg2, self.arg3) 元组,它产生生成器。这是由你使用 yield __下一个__ __下一个__ 方法应该 返回 价值观,而不是 他们。看到了吗 this question

        3
  •  2
  •   blhsing    6 年前

    __next__ 如果要返回的项目数可变,则此选项非常有用。由于迭代器要产生的属性数量是固定的,因此可以简单地使用 iter 函数从这三个属性创建迭代器,并使 __iter__ 方法返回迭代器:

    class Test(object):
    
        def __init__(self, arg):
            self.arg1 = arg + 1
            self.arg2 = arg + 2
            self.arg3 = arg + 3
    
        def __iter__(self):
            return iter((self.arg1, self.arg2, self.arg3))
    

    相当于,不使用 功能:

    class Test(object):
        class Iter:
            def __init__(self, lst):
                self.lst = lst
                self.index = 0
    
            def __next__(self):
                if self.index == len(self.lst):
                    raise StopIteration()
                value = self.lst[self.index]
                self.index += 1
                return value
    
        def __init__(self, arg):
            self.arg1 = arg + 1
            self.arg2 = arg + 2
            self.arg3 = arg + 3
    
        def __iter__(self):
            return self.Iter((self.arg1, self.arg2, self.arg3))
    
        4
  •  1
  •   stovfl    6 年前

    问题 :如何将对象解包为for循环中的元组?

    Test(object)
    tuple(arg1, arg2, arg3) 从物体上,你必须触发它。

    1. 使用 iter

      class Test(object):
         ...
         def __iter__(self):
             yield self.arg1
             yield self.arg2
             yield self.arg3
      
      
      for arg1, arg2, arg3 in map(iter, test_list):
          print('arg1', arg1, 'arg2', arg2, 'arg3', arg3)
      

      或武力 .format(... t 作为类型 tuple

      for t in test_list:
          print("arg1={}, arg2={}, arg3={}".format(*tuple(t)))
      

    1. 使用类属性 values(self, ...

      class Test(object):
         ...
          #@property
          def values(self):
              return self.arg1, self.arg2, self.arg3
      
      
      for arg1, arg2, arg3 in map(Test.values, test_list):
          print('arg1', arg1, 'arg2', arg2, 'arg3', arg3)
      

      。格式(。。。 *

      for t in test_list:
          print("arg1={}, arg2={}, arg3={}".format(*t.values()))
      

    1. 建议使用。没有任何 :

      for t in test_list:
          print('arg1', t.arg1, 'arg2', t.arg2, 'arg3', t.arg3)
      

      或与 。格式(。。。

      for t in test_list:
          print("arg1={t.arg1}, arg2={t.arg2}, arg3={t.arg3}".format(t=t))