How to create a read-only class property in Python?
The property
descriptor always returns itself when accessed from a class (ie. when instance
is None
in its __get__
method).
If that's not what you want, you can write a new descriptor that always uses the class object (owner
) instead of the instance:
>>> class classproperty(object):
... def __init__(self, getter):
... self.getter= getter
... def __get__(self, instance, owner):
... return self.getter(owner)
...
>>> class Foo(object):
... x= 4
... @classproperty
... def number(cls):
... return cls.x
...
>>> Foo().number
4
>>> Foo.number
4
When should an attribute be private and made a read-only property?
Generally, Python programs should be written with the assumption that all users are consenting adults, and thus are responsible for using things correctly themselves. However, in the rare instance where it just does not make sense for an attribute to be settable (such as a derived value, or a value read from some static datasource), the getter-only property is generally the preferred pattern.
Make a class instance attribute read-only in Python
It looks fine to me, except one thing: _path = None
belongs to a class.
This is just a small improvment:
class DataFolder(object):
def __init__(self, owner, path):
self._path = None # now it is an instance variable.
self.path = path
self.owner = owner
@property
def owner(self):
return self._owner
def _validate_owner(self, owner_value):
if "me" not in owner_value:
raise ValueError("invalid owner")
@owner.setter
def owner(self, owner_value):
self._validate_owner(owner_value)
self._owner = owner_value
@property
def path(self):
return self._path
def _validate_path(self, path_value):
if self._path is not None:
raise AttributeError("Cannot edit path of existing data folder")
if "dat" not in path_value:
raise ValueError("invalid folder")
@path.setter
def path(self, path_value):
self._validate_path(path_value)
self._path = path_value
Using:
d = DataFolder('me', 'data')
print(d.path, d.owner)
d.path = 'new_data'
Output:
('data', 'me')
new_me
AttributeError: Cannot edit path of existing data folder
How to create object having read-only attributes dynamically
Consider starting with __setattr__
:
>>> class ReadOnlyClass:
... def __init__(self, **kwargs):
... self.__dict__.update(kwargs)
...
... def __setattr__(self, key, value):
... raise AttributeError("can't set attribute")
...
>>> readonly_object = ReadOnlyClass(name='Tom', age=24)
>>> readonly_object.name
'Tom'
>>> readonly_object.age
24
>>> readonly_object.age = 10
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __setattr__
AttributeError: can't set attribute
However, this may not fully meet your expectations. You can still set the attributes through __dict__
:
>>> readonly_object.__dict__['age'] = 10
>>> readonly_object.age
10
Shorter way to make properties read-only
At the very least, you could just call property
as a function, rather than using it as a decorator. At the same time, you can store the underlying values in a list or dict rather than as separate attributes.
class MyClass(object):
def __init__(self):
self._values = [...]
a = property(lambda self: self._values[0])
b = property(lambda self: self._values[1])
# etc
However, a read-only property doesn't really need to store its value in the instance dict; just hard-code the value directly in the getter:
class MyClass(object):
a = property(lambda self: "foo")
b = property(lambda self: "bar")
And then wrap the call to property in another function :)
def constant(value):
def _(self):
return value
return property(_)
class MyClass(object):
a = constant("foo")
b = constant("bar")
Here's a pure-Python read-only property, modeled after the example shown at https://docs.python.org/3/howto/descriptor.html#properties:
class Constant(object):
def __init__(self, value)
def _(self):
return value
self.fget = _
def __get__(self, obj, objtype=None):
if obj is None:
return self
return self.fget(obj)
This is probably simpler than subclassing property
and overriding __set__
and __del__
to "unimplement" them. But, I like my idea of a wrapper around a regular property better.
How to set a read-only @property in __init__
Functions are 1st class citizens in python. You cant have two members in your class that are named exactly the same. Essentially your class already has a self.value
of type <class 'property'>
that your code tries to set to a integer given as value
which is forbidden - so this error pop up.
Circumvent it by:
class A:
def __init__(self, value: int):
self._value = value # private backer
@property
def value(self):
return self._value
my_a = A(22) # works, no error
print(my_a.value) # 22
How should I expose read-only fields from Python classes?
I would use property
as a decorator to manage your getter for name
(see the example for the class Parrot
in the documentation). Use, for example, something like:
class Article(object):
def __init__(self, name, available):
self._name = name
self.available = available
@property
def name(self):
return self._name
If you do not define the setter for the name
property (using the decorator x.setter
around a function) this throws an AttributeError
when you try and reset name
.
Note: You have to use Python's new-style classes (i.e. in Python 2.6 you have to inherit from This is not the case according to @SvenMarnach.object
) for properties to work correctly.
python read-only class properties
Use a metaclass
class MetaVector3(type):
@property
def zero(cls):
return cls(0,0,0)
class Vector3(object):
__metaclass__ = MetaVector3
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
>>> v = Vector3.zero
>>> v.x, v.y, v.z
(0, 0, 0)
Related Topics
Defining Private Module Functions in Python
How Many Concurrent Requests Does a Single Flask Process Receive
Django Datetime Issues (Default=Datetime.Now())
Print All Day-Dates Between Two Dates
Different Ways of Clearing Lists
Error Installing Psycopg2, Library Not Found for -Lssl
How to Specify Your Own Distance Function Using Scikit-Learn K-Means Clustering
How to Check If a Value Exists in a Dictionary
How to Efficiently Calculate a Running Standard Deviation
How to Perform HTML Decoding/Encoding Using Python/Django
Convert Image from Pil to Opencv Format
Calculating Arithmetic Mean (One Type of Average) in Python
Angles Between Two N-Dimensional Vectors in Python
How to Write Inline If Statement for Print
How to Change Plot Background Color
What Are Good Uses for Python3's "Function Annotations"
What Is the Best (Idiomatic) Way to Check the Type of a Python Variable