Iterating over objects of a class

2008-12-24 Thread 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
--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over objects of a class

2008-12-24 Thread Diez B. Roggisch

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
--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over objects of a class

2008-12-24 Thread MRAB

Diez B. Roggisch wrote:

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

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

--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over objects of a class

2008-12-24 Thread Kottiyath
On Dec 24, 10:52 pm, "Diez B. Roggisch"  wrote:
> 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

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
--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over objects of a class

2008-12-24 Thread Kottiyath
On Dec 24, 11:04 pm, MRAB  wrote:
> Diez B. Roggisch wrote:
> > 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 :)
>
> 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?
--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over objects of a class

2008-12-24 Thread Gabriel Genellina
En Wed, 24 Dec 2008 16:18:55 -0200, Kottiyath   
escribió:



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?


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


--
Gabriel Genellina

--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over objects of a class

2008-12-24 Thread Kottiyath
On Dec 24, 11:48 pm, "Gabriel Genellina" 
wrote:
> En Wed, 24 Dec 2008 16:18:55 -0200, Kottiyath   
> escribió:
>
> >> 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?
>
> 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).
>
> --
> Gabriel Genellina

Thank you very much, Gabriel.
I am very thankful to everyone.
--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over objects of a class

2008-12-24 Thread Scott David Daniels

Kottiyath wrote:

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


Search for weakref in the documentatione.
In this case, I'd use a WeakValueDictionary() from id(obj) to obj.
Note id(obj) is guaranteed to be unique for all objects in existance,
but the id of a collected object may match the id of a new object.

>>> import weakref
>>> d = weakref.WeakValueDictionary()
>>> vs = [Int(n) for n in range(3, 500, 70)]
>>> for n in vs:
d[id(n)] = n
v = Int(n+1)
d[id(v)] = v
>>> for obj in d.values(): # values is safer than itervalues
print obj
>>> # note the above was the following, which fails:
>>> for v in d.values(): # values is safer than itervalues
print v


For extra credit, explain why values is better.

--Scott David Daniels
scott.dani...@acm.org
--
http://mail.python.org/mailman/listinfo/python-list