Are there some way to use the class attribute from parent inside child but do not inherit it?
class CycleFactory: all_cycles = [202015, 202016, 202017, 202101] class Cycle(int, CycleFactory): def __init__(self, cycle): self.cycle = cycle def __add__(self, other): return self.all_cycles[self.all_cycles.index(self.cycle) + other] def __sub__(self, other): return self.all_cycles[self.all_cycles.index(self.cycle) - other]
This is the example code. The point is that I’ll create many instances of Cycle
class and it’s running out of memory because the all_cycles
attribute has much more items than the example, but it’s fixed to all instances of Cycle
.
How could I achieve this? Use just one fixed attribute on a parent class to do not recreate it every time when I use the child class?
I thought about using the Factory and Abstract factory patterns, but they are not related to attributes, only creating new objects using a class Factory.
Advertisement
Answer
Your assumptions are wrong.
cycle1 = Cycle(CycleFactory.all_cycles[0]) cycle2 = Cycle(CycleFactory.all_cycles[1]) print(cycle1.cycle) # 202015 print(cycle2.cycle) # 202016 print(id(cycle1.all_cycles)) # 2442385684104 print(id(cycle2.all_cycles)) # 2442385684104
What this shows is that the two Cycle
instances share the same reference. It is because CycleFactory.all_cycles
is not an instance variable but a class variable, shared among all instances of this class and its subclasses. Proof is that :
cycle1.all_cycles.append(-159) print(cycle1.all_cycles) # [202015, 202016, 202017, 202101, -159] print(cycle2.all_cycles) # [202015, 202016, 202017, 202101, -159]
I modified only for cycle1
but cycle2
also sees the modification. It is because they don’t have each a copy, but each a reference. You may be interested to read the Python’s Data Model first chapter about references and (im)mutability. In C parlance, we would call the distinction “value versus pointer”.
So your assumption that each Cycle
has its own copy, thus blowing up the memory usage, is incorrect. Each only have a reference (pointer), which is of negligible size, except if you intend to have millions of Cycle
instances.
You should measure to be sure what is causing problems, cf How do I profile memory usage in Python?.
For performance problems (memory consumption here), the answer rarely comes from design patterns.
If your all_cycles
array is very very large, I recommend you to not use lists. You seem to never modify it, so you could use a tuple
instead, thus the change would just be :
all_cycles = (202015, 202016, 202017, 202101) # parentheses ^ ^
But if it is not enough or if you should be able to modify it, consider using something other than native lists. For example, numpy arrays are much more memory-efficient, see What are the advantages of NumPy over regular Python lists?