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 for
s 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]
>>>