Python中的类级别只读属性
是否有某种方法可以在Python中创建类级别的只读属性?举例来说,如果我有一个类Foo
,我想说:Python中的类级别只读属性
x = Foo.CLASS_PROPERTY
而是阻止任何人说:
Foo.CLASS_PROPERTY = y
编辑: 我喜欢的Alex Martelli's solution简单,但不它需要的语法。无论他和~unutbu's answer默示以下解决方案,这是接近到的精神是我一直在寻找:
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
s不“行为”像朴素的价值观。例如,我无法将它用作类中某个方法的参数的默认值。
发现这对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()
请注意,如果您尝试设置只读属性(t.a = 2
)Python会引发一个AttributeError
。
这适用于实例级属性,但不适用于(即我仍然不能说'ROClass.a',并期望值为'1')。 – mjumbewu 2009-11-14 20:59:18
Pynt引用的ActiveState solution使得ROClass的实例具有只读属性。你的问题似乎在问这个类本身是否可以具有只读属性。
这里有一种方法,基于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
的想法是这样的:首先考虑雷蒙德赫廷杰的解决方案:
class Bar(object):
CLASS_PROPERTY = property(lambda self: 1)
bar=Bar()
bar.CLASS_PROPERTY=2
它显示了一个比较简单的方法,让巴读 - 只有财产。
请注意,您必须将CLASS_PROPERTY = property(lambda self: 1)
行添加到bar类的定义中,而不是禁止自身。
所以,如果你想在类Foo
有一个只读属性,然后父类的Foo
必须有CLASS_PROPERTY = property(lambda self: 1)
定义。
一个类的父类是一个元类。因此我们定义ROType作为元类:
class ROType(type):
CLASS_PROPERTY = readonly(1)
然后我们做Foo的父类是ROType:
class Foo(object):
__metaclass__=ROType
现在我觉得自己像一个白痴,没有仔细阅读评论>。 2009-11-14 21:26:17
现有的解决方案是一个有点复杂 - 大约只保证什么,在一定的各班组具有唯一的元类,然后在自定义元类上设置正常的只读属性。即:
>>> 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
只是它确实是只读的确认!
为什么有人会尝试设置Foo.CLASS_PROPERTY? Python中的典型风格是在规划时选择简单性,以防止某个人做某些愚蠢的理论实例。你无法做任何事情来阻止人们用你的代码来做愚蠢的事情。 – 2009-11-14 23:15:27
@Mike:你是对的;常识会告诉人们不要修改这些属性。然而,偶尔他们会被修改。这就是为什么我喜欢它被拼写出来(比全部大写更明确)。与使用私人会员的理由相同。显式接口很好。不要误解我的意思:我也喜欢简单。我更喜欢如果有一些内置的设施(比如@classproperty装饰器或其他)。事实上,如果每次都需要设置'__metaclass__',我甚至不确定是否会使用上述解决方案。现在,全部大写可能会赢。 – mjumbewu 2009-11-15 00:07:22
未来人们的注意事项:现代python版本可以在新式类中使用'@ property':http://docs.python.org/library/functions.html#property – 2012-06-07 15:12:35