I will not try to guess your need so I will assume you mean exactly what you said below, namely that you want a single initialization of a class member, but done through the creation of an instance.
a class member of TaskInput, ie, TaskInput.cfg = my_config, something
that's initialized in init() of TaskInput.
This can work, but not the way you did it. in your code you never created a class attribute, anything created with self is an instance attribute belonging to a single specific task instance so that:
from copy import deepcopy
class TaskInput:
_cfg = None # prefix with '_' to indicate it should be considered private
def __init__(self, my_config=None):
_cfg = _cfg or my_config
@property
def cfg(self):
""" If you want to privatize it a bit more,
make yourself a getter that returns a deep copy."""
return deepcopy(cfg)
Now, there basically is no such thing as true privatization in python and you will never be able to entirely prevent manipulation. In the example above, any child has direct read-write access to _cfg
, so it would fall on us not to use it directly and pass by its accessors (__init__()
and cfg()
).
There's always a way to make things more difficult, like the following, using modules.
Project
├─ __init__.py
├─ settings.py
├─ module1.py
└─ module2.py
settings.py
cfg = None
module1.py
from copy import deepcopy
import settings
class A:
def __init__(self, cfg_=None):
settings.cfg = settings.cfg or cfg_
@property
def cfg(self):
return deepcopy(settings.cfg)
module2.py
""" The following classes won't be able to
overwrite the config without importing
from settings.py.
"""
from module1 import A
class B(A):
pass
class C(A):
def __init__(self):
super().__init__("foobar")
Giving these results:
b0 = B()
b0.cfg
# > None
b1 = B({"foo1": "bar1"})
b1.cfg
# > {'foo1': 'bar1'}
b2 = B({"foo1": "bar2", "foo3": "bar3"})
b2.cfg
# > {'foo1': 'bar1'}
try:
b2.cfg = 1234
except Exception as e:
print(type(e), e)
# > <class 'AttributeError'> can't set attribute
b2.cfg
# > {'foo1': 'bar1'}
c = C("asdf")
c.cfg
# > {'foo1': 'bar1'}
Which can be overkill of course and removes the actual ownership of the configuration from the class