20

Given a class that keeps a registry of its Objects:

class Person(object):
   __registry = []

   def __init__(self, name):
       self.__registry.append(self)
       self.name = name

How would I make the following code work (without using Person.__registry):

for personobject in Person:
    print personobject

While researching I found a hint that one could go for a __metaclass__ with a __getitem__-method. Any ideas how this would look like?

1
  • ehh don't make an ugly hack look pretty. Commented Apr 11, 2009 at 11:29

3 Answers 3

33

You can make your class object iterable with a simple metaclass.

class IterRegistry(type):
    def __iter__(cls):
        return iter(cls._registry)

class Person(object):
    __metaclass__ = IterRegistry
    _registry = []

    def __init__(self, name):
        self._registry.append(self)
        self.name = name

(I have also changed __registry to _registry to make it easier to access from the metaclass). Then,

>>> p = Person('John')
>>> p2 = Person('Mary')
>>> for personobject in Person:
...     print personobject
...
<person.Person object at 0x70410>
<person.Person object at 0x70250>
Sign up to request clarification or add additional context in comments.

6 Comments

Really nice tip: I didn't know this one :)
Why doesn't this work with just putting the def iter in the Person class? Just wondering.
@Paolo Putting iter in the Person class makes Person instances iterable, putting it in the metaclass makes the Person class itself iterable, which is what we want here.
Hi, I have tested this piece of code in Python 3.6.0 Anaconda 64-bit and it does not work. I fixed the print statement but you get a TypeError: 'type' object is not iterable. I am a newby in Python but I guess this is probably because the specifications for an iterable object have been changed in Python 3.6.
_registery doesn't get updated when you delete instances of the class though.
|
17

First, do not use double __ names. They're reserved for use by Python. If you want "private" use single _.

Second, keep this kind of thing as simple as possible. Don't waste a lot of time and energy on something complex. This is a simple problem, keep the code as simple as possible to get the job done.

class Person(object):
    _registry = []

    def __init__(self, name):
        self._registry.append(self)
        self.name = name

for p in Person._registry:
    print p

1 Comment

The point is that the _registry solution is the simplest possible way to do this. Anything else is just trying to "put lipstick on a pig".
4

you can do it with:

for item in Person.__registry:
    print(item)

2 Comments

thats obvious... but i would like to make it work like: for item in Classname ... (just for the beauty of it...)
you need to make your class iterable then, I guess

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.