Skip to content
Advertisement

Use the parent’s attribute but do not inherit it on child using python

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?

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement