[ACCEPTED]-Class-level read-only properties in Python-python
The existing solutions are a bit complex 12 -- what about just ensuring that each class 11 in a certain group has a unique metaclass, then 10 setting a normal read-only property on the 9 custom metaclass. Namely:
>>> class Meta(type):
... def __new__(mcl, *a, **k):
... uniquemcl = type('Uniq', (mcl,), {})
... return type.__new__(uniquemcl, *a, **k)
...
>>> class X: __metaclass__ = Meta
...
>>> class Y: __metaclass__ = Meta
...
>>> type(X).foo = property(lambda *_: 23)
>>> type(Y).foo = property(lambda *_: 45)
>>> X.foo
23
>>> Y.foo
45
>>>
this is really 8 much simpler, because it's based on nothing 7 more than the fact that when you get an 6 instance's attribute descriptors are looked 5 up on the class (so of course when you get 4 a class's attribute descriptors are looked 3 on the metaclass), and making class/metaclass 2 unique isn't terribly hard.
Oh, and of course:
>>> X.foo = 67
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
just 1 to confirm it IS indeed read-only!
The ActiveState solution that Pynt references makes instances 14 of ROClass have read-only attributes. Your 13 question seems to ask if the class itself 12 can have read-only attributes.
Here is one 11 way, based on Raymond Hettinger's comment:
#!/usr/bin/env python
def readonly(value):
return property(lambda self: value)
class ROType(type):
CLASS_PROPERTY = readonly(1)
class Foo(object):
__metaclass__=ROType
print(Foo.CLASS_PROPERTY)
# 1
Foo.CLASS_PROPERTY=2
# AttributeError: can't set attribute
The idea is this: Consider 10 first Raymond Hettinger's solution:
class Bar(object):
CLASS_PROPERTY = property(lambda self: 1)
bar=Bar()
bar.CLASS_PROPERTY=2
It shows 9 a relatively simple way to give bar a read-only 8 property.
Notice that you have to add the 7 CLASS_PROPERTY = property(lambda self: 1)
line to the definition of the class of 6 bar, not to bar itself.
So, if you want the 5 class Foo
to have a read-only property, then 4 the parent class of Foo
has to have CLASS_PROPERTY = property(lambda self: 1)
defined.
The 3 parent class of a class is a metaclass. Hence 2 we define ROType as the metaclass:
class ROType(type):
CLASS_PROPERTY = readonly(1)
Then we 1 make Foo's parent class be ROType:
class Foo(object):
__metaclass__=ROType
Found this on ActiveState:
# simple read only attributes with meta-class programming
# method factory for an attribute get method
def getmethod(attrname):
def _getmethod(self):
return self.__readonly__[attrname]
return _getmethod
class metaClass(type):
def __new__(cls,classname,bases,classdict):
readonly = classdict.get('__readonly__',{})
for name,default in readonly.items():
classdict[name] = property(getmethod(name))
return type.__new__(cls,classname,bases,classdict)
class ROClass(object):
__metaclass__ = metaClass
__readonly__ = {'a':1,'b':'text'}
if __name__ == '__main__':
def test1():
t = ROClass()
print t.a
print t.b
def test2():
t = ROClass()
t.a = 2
test1()
Note that if you try to set 2 a read-only attribute (t.a = 2
) python will raise 1 an AttributeError
.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.