Home > Software engineering >  TypeError: INT object is not iterable while defining a custom iterator
TypeError: INT object is not iterable while defining a custom iterator

Time:10-11

I am tying to make my custom class iterable by defining an iterator based on Vijay Shankar's answer here:

import numpy as np
import itertools

class MyClass():
    id = itertools.count()

    def __init__(self, location = None):
        self.id = next(MyClass.id)
        self.location = np.random.uniform(0, 1, size=(1, 2)).tolist()

    def __iter__(self):
        for _ in self.__dict__.values():
            yield _

def create():
    objects = []
    objects.append(MyClass())
    counter = 1
    while counter != 20:
        new_object = MyClass()
        objects.append(new_object)
        counter = counter   1
    return objects

objects = create()
objects = [[item for subsublist in sublist for item in subsublist] for sublist in objects]

However, I still get this error

objects = [[item for subsublist in sublist for item in subsublist] for sublist in objects]
TypeError: 'MyClass' object is not iterable

How can I fix this problem?

Edit:

Currently, this is what the iterator returns:

>>> print([x for x in create()[0]])
[20, [[0.2552026126490259, 0.48489389169530417]]]

How should one revise it so that it returns like below?

>>> print([x for x in create()[0]])
[20, [0.2552026126490259, 0.48489389169530417]]

CodePudding user response:

Your code has one too many iterations:

[[item for subsublist in sublist for item in subsublist] for sublist in objects]

I count 3 fors Meaning 3 iterations. The first iterations would be the list from create() into the MyClass() objects. The second iteration would be the attributes of each MyClass() The third would attempt to iterate over location/id/whatever other properties the class has. This isn't safe because the property id (int) is not an iterator.

List[MyClass] -> MyClass -> Properties of MyClass (id/location) -> ERROR

Your iterator is working. Here's an iteration over just a single MyClass():

print([x for x in create()[0]])
>>> [20, [[0.2552026126490259, 0.48489389169530417]]]

If you want to expand a list of your class (instead of just one as I did above)

my_classes = create()
objects = [[attribute for attribute in my_class] for my_class in my_classes]
print(objects)
>>>[[0, [[0.7226935825759357, 0.18522688980137658]]], [1, [[0.1660964810272717, 0.016810136422152677]]], [2, [[0.1611089351209548, 0.3935547119768953]]], [3, [[0.4589556901947873, 0.18405198063215056]]], [4, [[0.811343515881961, 0.6123114388786854]]], [5, [[0.38830918188777996, 0.23119360704055836]]], [6, [[0.3269834811013743, 0.3608326475799025]]], [7, [[0.9971686351479419, 0.7054058805215702]]], [8, [[0.11316919241038192, 0.07453424664431929]]], [9, [[0.5548059787590179, 0.062422711183232615]]], [10, [[0.38567389514423267, 0.659106105987059]]], [11, [[0.973277039327461, 0.2821071201116454]]], [12, [[0.16566758369419543, 0.3010363002131601]]], [13, [[0.923317671409532, 0.30016022638587536]]], [14, [[0.9757923181511164, 0.5888806462517852]]], [15, [[0.5582498753119571, 0.27190786180188264]]], [16, [[0.28120075553258217, 0.6873211952682786]]], [17, [[0.7016575026994472, 0.5820325771264436]]], [18, [[0.5815482608888624, 0.22729004063915448]]], [19, [[0.2009082164070768, 0.11317171355184519]]]]

Additionally. You may as well use yield from here. As you're yielding another iterable.

class MyClass():
    id = itertools.count()

    def __init__(self, location = None):
        self.id = next(MyClass.id)
        self.location = np.random.uniform(0, 1, size=(1, 2)).tolist()

    def __iter__(self):
        yield from self.__dict__.valies()

EDIT:

Per your question on location being a nested list instead of a list just throw away that extra dimension when you assign to self.location.

print(np.random.uniform(0, 1, size=(1, 2)).tolist())
>>> [[0.3649653171602294, 0.8447097505387996]]
print(np.random.uniform(0, 1, size=(1, 2)).tolist()[0])
[0.247024738276844, 0.9303441776787809]
>>> 
  • Related