I would like to setup an object that imports some raw_data during the initialization phase of the object (ie during the __init__()
method). However I would like to make it read only from that point on. I was thinking of using a setter property self.raw_data
with the following logic:
@raw_data.setter
def raw_data(self, dataframe):
<IF calling from __init__>?
self.__raw_data = df
Is there a way for the setter method to know if it is being called from within __init__
? Blocking all other attempts to change the data.
The closest you can get is to only allow to set self._raw_data
if it hasn't be set yet, ie:
class Foo(object):
def __init__(self, dataframe):
self.raw_data = dataframe
@property
def raw_data(self):
return getattr(self, '_raw_data', None)
@raw_data.setter
def raw_data(self, dataframe):
if hasattr(self, '_raw_data'):
raise AttributeError, "Attribute is read-only")
self._raw_data = dataframe
Which makes the setter mostly useless, so you'd get the same result with less code skipping it (which will make the property read-only):
class Foo(object):
def __init__(self, dataframe):
self._raw_data = dataframe
@property
def raw_data(self):
return self._raw_data
But beware that none of these solutions will prevent you to directly set _raw_data
.
Nothing you do in the raw_data
setter is going to stop direct assignment to __raw_data
. I would recommend not defining a setter and using __raw_data
for initialization. This will block writes to raw_data
, but not __raw_data
.
If you want stricter enforcement, then by design, you don't have many options. One option is to write your class in C or Cython. The other option is easier, but it has awkward side effects. That option is to subclass an immutable built-in type, such as tuple
, and create pre-initialized instances with __new__
instead of mutating them into an initialized state with __init__
:
class Immutable(tuple):
__slots__ = [] # Prevents creation of instance __dict__
def __new__(cls, *whatever_args):
attribute1 = compute_it_however()
attribute2 = likewise()
return super(cls, Immutable).__new__(cls, attribute1, attribute2)
@property
def attribute1(self):
return self[0]
@property
def attribute2(self):
return self[1]
This makes your objects immutable, but the awkward side effect is that your objects are now tuples.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.