[英]Class-level read-only properties in Python
有没有办法在Python中创建类级别的只读属性? 例如,如果我有一个Foo
类,我想说:
x = Foo.CLASS_PROPERTY
但是阻止任何人说:
Foo.CLASS_PROPERTY = y
编辑:我喜欢Alex Martelli解决方案的简单性,但不喜欢它需要的语法。 他和~ututbu的答案都启发了以下解决方案,这更接近我所寻找的精神:
class const_value (object):
def __init__(self, value):
self.__value = value
def make_property(self):
return property(lambda cls: self.__value)
class ROType(type):
def __new__(mcl,classname,bases,classdict):
class UniqeROType (mcl):
pass
for attr, value in classdict.items():
if isinstance(value, const_value):
setattr(UniqeROType, attr, value.make_property())
classdict[attr] = value.make_property()
return type.__new__(UniqeROType,classname,bases,classdict)
class Foo(object):
__metaclass__=ROType
BAR = const_value(1)
BAZ = 2
class Bit(object):
__metaclass__=ROType
BOO = const_value(3)
BAN = 4
现在,我得到:
Foo.BAR
# 1
Foo.BAZ
# 2
Foo.BAR=2
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: can't set attribute
Foo.BAZ=3
#
我更喜欢这个解决方案因为
type(X).foo = ...
它仍然不理想,因为:
__metaclass__
以便正确解释const_value
对象。 const_value
不像普通值那样“表现”。 例如,我无法将其用作类中方法的参数的默认值。 现有的解决方案有点复杂 - 只需确保某个组中的每个类都有一个唯一的元类,然后在自定义元类上设置一个普通的只读属性。 即:
>>> 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
>>>
这实际上要简单得多,因为它只是基于这样一个事实:当你获得一个实例时,属性描述符会在类上查找(当然,当你得到一个类的属性描述符被查看在元类上时),并且创建类/元类独特并不是特别难。
哦,当然:
>>> X.foo = 67
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
只是为了确认它确实是只读的!
Pynt引用的ActiveState解决方案使ROClass的实例具有只读属性。 您的问题似乎在询问类本身是否具有只读属性。
根据Raymond Hettinger的评论 ,这是一种方式:
#!/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
这个想法是这样的:首先考虑Raymond Hettinger的解决方案:
class Bar(object):
CLASS_PROPERTY = property(lambda self: 1)
bar=Bar()
bar.CLASS_PROPERTY=2
它显示了一种为bar提供只读属性的相对简单的方法。
请注意,您必须将CLASS_PROPERTY = property(lambda self: 1)
行添加到bar类的定义中,而不是bar本身。
因此,如果您希望类Foo
具有只读属性,则Foo
的父类必须CLASS_PROPERTY = property(lambda self: 1)
。
类的父类是元类。 因此我们将ROType定义为元类:
class ROType(type):
CLASS_PROPERTY = readonly(1)
然后我们让Foo的父类为ROType:
class Foo(object):
__metaclass__=ROType
在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()
请注意,如果您尝试设置只读属性( ta = 2
),python将引发AttributeError
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.