Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it always bad to collect all instances in a class variable?

Consider two versions of a simple weather model which stores the location of clouds:

class cloud:
    def __init__(self, x, y):
        self.x = x
        self.y = y

collection = []
collection.append(cloud(1,2))
collection.append(cloud(4,6))

def update_all_clouds(collection):
    for c in collection:
        cloud.x += 1
        cloud.y += 1

update_all_clouds(collection)

vs

class cloud:
    collection = []
    def __init__(self, x, y)
        self.x = x
        self.y = y
        cloud.collection.append(self)
    @classmethod
    def update_all(cls):
        for c in cloud.collection:
            c.x += 1
            c.y += 1
cloud(1,2)
cloud(4,6)
cloud.update_all()

This has basically been punished here Is it bad to store all instances of a class in a class field? but there is an emphasis here on class methods which act on all instances. Is there nothing to be said for the simplicity of the last three lines that the second approach affords?

I am aware that another approach would be creating a list-like class called, for example, collection and giving that class methods like update_all() but to me it doesn't seem much better.

like image 416
hlud6646 Avatar asked Jul 09 '15 06:07

hlud6646


People also ask

Are class variables good practice?

However, is this considered good practice? Is there a better way to do it? Class variables certainly have their use, specifically for cases where data is shared across all instances... So, yes, if this does what you want and it fits the use case, it's fine.

Does a class need instance variables?

Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class.

Are class variables shared between instances?

var should definitely not be shared as long as you access it by instance. var or self. var . With the list however, what your statement does is when the class gets evaluated, one list instance is created and bound to the class dict, hence all instances will have the same list.

Can an object have more than one instance variable?

All instances of an object have their own copies of instance variables, even if the value is the same from one object to another. One object instance can change values of its instance variables without affecting all other instances.


3 Answers

In general, this is bad, yes, for the simple reason that the objects being in a list keeps a reference to them pretty much forever. There being a reference to an object prevents it from being garbage collected. So objects of your type essentially live forever (until the program terminates) and the memory they take up will never be freed.

Of course, if you have a very specific need for this, and are in full control of when the objects are created, you could do it like that. But in general explicit is better than implicit, so it’s a better idea to have an actual collection where you add those elements. That collection could even live in the type, so you could do:

obj = Cloud(…)
Cloud.add(obj)

# or even
obj = Cloud(…).persistInType()

You could also use weak references to avoid the problem described above, but that’s additional overhead, and a bit more complicated to manage. So just do yourself a favor, and collect the objects manually.

like image 65
poke Avatar answered Nov 02 '22 03:11

poke


Considering that explicit is better than implicit (see The Zen of Python) perhaps the best is approach is to have two classes: Cloud and CloudCollection. This would allow you to write code like this:

collection = CloudCollection()
collection.add(Cloud(1, 2))
collection.add(Cloud(4, 6))
collection.shift(1, 1)
like image 40
dlask Avatar answered Nov 02 '22 03:11

dlask


This question can simply be reduced to a question about using global variables, as a mutable class-level member is just a globlal variable in a different namespace.

All the arguments against using global variables apply to this as well.

like image 31
shx2 Avatar answered Nov 02 '22 03:11

shx2