Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python3 mutable static class members

Tags:

python-3.x

I have a need to use static classes functions a variables and all useable classes would inherit from a single parent that have all the common methods and variables.

Current behavior is that a class variable defined in the parent is not distict to each child and is shared among all childs (need it as discreed variable)

class Parent(object):
    cls_var = list()

    @classmethod
    def cls_mthd(cls, a):
        cls.cls_var.append(a)

class ChildA(Parent):
    pass

ChildA.cls_mthd('A')

class ChildB(Parent):
    pass

ChildB.cls_mthd('B')

print(Parent.cls_var)
print(ChildA.cls_var)
print(ChildB.cls_var)

Output

['A', 'B']
['A', 'B']
['A', 'B']

A workaround to get the desired behavior I managed to get is this, but I don't think this hack would be the best way to go

class Parent(object):
    cls_var = dict()

    @classmethod
    def cls_mthd(cls, a):
        if cls.__name__ not in cls.cls_var:
            cls.cls_var[cls.__name__] = list()
        cls.cls_var[cls.__name__].append(a)

    @classmethod
    def tst(cls):
        return cls.cls_var[cls.__name__] if cls.__name__ in cls.cls_var else None

class ChildA(Parent):
    pass

ChildA.cls_mthd('A')

class ChildB(Parent):
    pass

ChildB.cls_mthd('B')

print(Parent.tst())
print(ChildA.tst())
print(ChildB.tst())

Output

None
['A']
['B']
like image 278
Omri Abu Avatar asked Feb 15 '26 21:02

Omri Abu


1 Answers

in order to have mutable static class members you could use a metaclass:

class MutableClassVarMeta(type):
    def __new__(meta, name, bases, namespace, **kwds):
        cls = super().__new__(meta, name, bases, namespace, **kwds)
        cls.cls_var = []
        return cls

class Parent(metaclass=MutableClassVarMeta):
    @classmethod
    def cls_mthd(cls, a):
        cls.cls_var.append(a)

class ChildA(Parent):
    pass

class ChildB(Parent):
    pass

ChildA.cls_mthd('A')
ChildB.cls_mthd('B')

print(Parent.cls_var)  # []
print(ChildA.cls_var)  # ['A']
print(ChildB.cls_var)  # ['B']

(or did you really want None as Parent.cls_var?)

i admit it is a bit more verbose than your workaround but (to me) it looks more pythonic...


update

as pointed out by Blckknght the metaclass could (and probably should) look simpler:

class MutableClassVarMeta(type):
    def __init__(cls, name, bases, attrs):
        cls.cls_var = []
like image 50
hiro protagonist Avatar answered Feb 17 '26 11:02

hiro protagonist



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!