Iterating over objects of a class

Diez B. Roggisch deets at nospam.web.de
Wed Dec 24 12:52:50 EST 2008


Kottiyath schrieb:
> Hi,
>    How can I iterate over all the objects of a class?
>    I wrote the code like following:
> class baseClass(object):

Consider adopting PEP 8  coding conventions.


>     __registry = []
> 
>     def __init__(self, name):
>         self.__registry.append(self)
>         self.name = name
> 
>     def __iter__(self):
>         baseClass.item = 0
>         return self.__registry[0]
> 
>     def next(self):
>         if baseClass.item >= len(self.__registry):
>             raise StopIteration
>         baseClass.item += 1
>         return self.__registry[baseClass.item - 1]
> 
> For testing, create the following objects-
> a = baseClass("Test1")
> b = baseClass("Test2")
> 
> class subClass (baseClass):
>    pass
> c = subClass("Test3")
> 
> ---->Actual Iteration<----
> for i in a:
>     print i.name
> 
> Test1
> Test2
> Test3
> 
> ---------------------------------------------------
> I see the following problems in the code:
> 1. I have to iterate over any of the objects. For correctness, I
> wanted to iterate over the class, like
> for i in baseClass():
>    do x
> but that will will create one more object - which I do not want.
> 
> 2. If the subclass wants to do somethings in its constructor, I am not
> sure how to update the registry.
> class subClass (baseClass):
>    def __init__(self, name):
>        **do something**
>        super.init(self, name)  ----> This errors out, saying it needs
> super, not subClass

You don't show the actual traceback, however the idiom for invoking 
super for new-style-classes is


super(subClass, self).__init__(name)

for your case.

> Another method I thought of implementing it was using generators -
> where-in baseClass.objects() is a generator which will yield the
> objects one by one - but even then the second issue remains.
> If somebody can help me out, I would be very thankful.


Using a generator or not isn't the issue here.

What you need is a *class*-based access, not instance-based. There are 
various methods to accomplish this. The simplest is to ditch the 
obnoxious __registry as name, and just do

class BaseClass(object):

    REGISTRY = []


Then iterating is a simple matter of

for instance in BaseClass.REGISTRY:
    ...


Case solved. Alternatively, if you insist on the concept of privacy for 
that registry, you can use a classmethod:


class BaseClass(object):


    @classmethod
    def registry(cls):
        for i in cls.__registry:
            yield i





Last but not least you *could* go for a __metaclass__ with an 
__getitem__-method, that makes thinks look fancy because you then can do:


for instance in BaseClass:
     ...

I leave it as an exercise to you - gotta go christmas dining now :)

Diez



More information about the Python-list mailing list