0

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.

Henrique Branco
  • 1,778
  • 1
  • 13
  • 40

1 Answers1

1

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?

Lenormju
  • 4,078
  • 2
  • 8
  • 22