我尝试创建以下代码:
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列表的情况下解压缩python列表中的对象?对于最后一个示例,结果将是:
arg1 1 arg2 2 arg3 3
arg1 2 arg2 3 arg3 4
arg1 3 arg2 4 arg3 5
答案 0 :(得分:5)
问题是您的__next__
方法未正确实现。您使Test
类可迭代,但是它不会迭代您的想法:
>>> 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
方法内使用__next__
引起的。 __next__
方法应返回值,而不是 yield 。有关详细说明和修复,请参见this question。
答案 1 :(得分:2)
__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))
等同于不使用iter
函数:
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))
答案 2 :(得分:2)
您接近了,但是,您需要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
因此,为了避免在循环中进行额外的拆包,您必须通过循环遍历属性并一次生成每个属性来创建一系列生成的值。
答案 3 :(得分:1)
问题:由于对象是for循环中的元组,因此如何解包?
您错了,您在循环中遇到了Test(object)
。
要从对象中获取tuple(arg1, arg2, arg3)
,您必须触发它。
使用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)))
使用类属性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)
或带有 .format(...
和 *
for t in test_list:
print("arg1={}, arg2={}, arg3={}".format(*t.values()))
推荐用法。没有任何魔术:
for t in test_list:
print('arg1', t.arg1, 'arg2', t.arg2, 'arg3', t.arg3)
或带有.format(...
for t in test_list:
print("arg1={t.arg1}, arg2={t.arg2}, arg3={t.arg3}".format(t=t))
使用Python测试:3.5