Iterating over objects of a class
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
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
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
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
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
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
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
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