Reputation: 206
I have defined the following class
class Person(object):
_counter = 0
_instances = []
def __init__(self, nam):
self.name = nam
self._instances.append(self)
self._id = Person._counter + 1
Person._counter+=1
def __repr__(self):
return f'{self._id} : Person({self.name})'
def __iter__(self):
return self
def __next__(self):
pass
@classmethod
def iterate(cls):
return [p for p in Person._instances]
I can iterate over the instances of this class with
[p for p in Person._instances]
I would like to learn how it is possible to arrive at the same result by calling
[p for p in Person]
I have searched many similar questions and I tried out several suggested answers, without any luck. I am using Python 3.6 Anaconda x64 and in all the solutions I tested on the interpreter I am getting back
[p for p in Person]
TypeError: 'type' object is not iterable
Could you please write exactly how I can execute successfully this [p for p in Person] call to get back the same list as Person.iterate() and Person._instances ?
Upvotes: 4
Views: 691
Reputation: 206
For clarity purposes I have included the solution and some testing data as it has already been pointed out by "Moses Koledoye" and there is also a useful comment by "chepner" which I tried to take on account.
class PersonMeta(type):
_counter = 0
_instances = []
def __iter__(self):
return iter(getattr(self, '_instances', []))
class Person(metaclass=PersonMeta):
def __init__(self, nam):
self.name = nam
Person._instances.append(self)
self._id = Person._counter + 1
Person._counter+=1
def __repr__(self):
return f'{self._id} : Person({self.name})'
In [70]: [p for p in Person]
Out[70]:
[1 : Person(James),
2 : Person(George),
3 : Person(Jack),
4 : Person(Mary),
5 : Person(Sue),
6 : Person(James),
7 : Person(George),
8 : Person(Jack),
9 : Person(Mary),
10 : Person(Sue)]
Ideally, I would like to see a more clear separation between the Metaclass and the Class. But I don't know how I can transfer the folowing statements to the MetaPerson. Is that a good idea ? Can you help me with this ?
Person._instances.append(self)
Person._counter+=1
Upvotes: 0
Reputation: 78536
You can define an __iter__
on the metaclass to make the metaclass instance (i.e. Person
) iterable:
class metaclass(type):
def __iter__(cls):
return iter(getattr(cls, '_instances', []))
class Person(metaclass=metaclass):
# __metaclass__ = metaclass Python 2
...
Upvotes: 9