मैंने निम्नलिखित कोड बनाने की कोशिश की:

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)

लेकिन जब मैं दौड़ने की कोशिश करता हूं, तो अजगर कहता है:

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)

वर्कअराउंड के प्रदर्शन के रूप में हम इसे स्पष्ट रूप से किए बिना पाइथन सूची में ऑब्जेक्ट्स को अनपैक कैसे कर सकते हैं? अंतिम उदाहरण के लिए, परिणाम इस प्रकार होगा:

arg1 1 arg2 2 arg3 3
arg1 2 arg2 3 arg3 4
arg1 3 arg2 4 arg3 5
6
user 26 अक्टूबर 2018, 10:54

4 जवाब

सबसे बढ़िया उत्तर

आप करीब हैं, हालांकि, आपको 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

इस प्रकार, लूप में अतिरिक्त अनपैकिंग से बचने के लिए, आपको विशेषताओं पर लूप करके और एक-एक करके उत्पन्न मूल्यों की एक धारा बनानी होगी।

7
Ajax1234 26 अक्टूबर 2018, 18:45

समस्या यह है कि आपकी __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) टपल उत्पन्न करने के बजाय, यह जेनरेटर उत्पन्न करता है। यह आपके द्वारा __next__ पद्धति के अंदर yield के उपयोग के कारण होता है। एक __next__ विधि को मान वापस होना चाहिए, न कि उन्हें उपज। विस्तृत विवरण और समाधान के लिए यह प्रश्न देखें।

6
Aran-Fey 26 अक्टूबर 2018, 08:19

__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
blhsing 26 अक्टूबर 2018, 08:43

प्रश्न: किसी ऑब्जेक्ट को कैसे अनपैक करें क्योंकि वह लूप के लिए एक टपल था?

आप गलत हैं, आपको लूप में एक 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)
    

    या .format(... और * . के साथ

    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)
    

    या .format(... के साथ

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

पायथन के साथ परीक्षण किया गया: 3.5

1
stovfl 26 अक्टूबर 2018, 15:25