Iterating over objects of a class

K

Kottiyath

Hi,
How can I iterate over all the objects of a class?
I wrote the code like following:
class baseClass(object):
__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

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.

Regards
K
 
D

Diez B. Roggisch

Kottiyath said:
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
 
M

MRAB

Diez said:
Kottiyath said:
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 :)
The other thing to remember is that because the 'registry' contains
references to the instances, they won't be garbage collected.
 
K

Kottiyath

Kottiyath said:
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

---------------------------------------------------
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

Thank you Very much, Diez. I was able to do the Generator and the
super part of it, but I never even thought of the metaclass option.
I will try it out. Thank you very much.
Merry Christmas.
P.S - >Also, I will use the PEP 8 coding conventions
 
K

Kottiyath

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.
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 :)

The other thing to remember is that because the 'registry' contains
references to the instances, they won't be garbage collected.

Is there any other way out in this case?
I have factory methods - and I have to loop over them - sort of Chain
of Responsibility pattern.
Having a registry inside the class instance and looping through them
was the only clean thing I could think of.
I understand that garbage collection would be an issue - but is there
any way out?
 
G

Gabriel Genellina

Is there any other way out in this case?
I have factory methods - and I have to loop over them - sort of Chain
of Responsibility pattern.
Having a registry inside the class instance and looping through them
was the only clean thing I could think of.
I understand that garbage collection would be an issue - but is there
any way out?

You may keep all that structures - just use weak references (see the
weakref module).
There isn't a WeakList nor WeakSet out-of-the-box but you may use a
WeakKeyDictionary (set the value to anything, None by example).
 
K

Kottiyath

You may keep all that structures - just use weak references (see the  
weakref module).
There isn't a WeakList nor WeakSet out-of-the-box but you may use a  
WeakKeyDictionary (set the value to anything, None by example).

Thank you very much, Gabriel.
I am very thankful to everyone.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top