Python 中的类级只读属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1735434/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Class-level read-only properties in Python
提问by mjumbewu
Is there some way to make a class-level read-only property in Python? For instance, if I have a class Foo
, I want to say:
有没有办法在Python 中创建类级只读属性?例如,如果我有一个 class Foo
,我想说:
x = Foo.CLASS_PROPERTY
but prevent anyone from saying:
但要防止任何人说:
Foo.CLASS_PROPERTY = y
EDIT:I like the simplicity of Alex Martelli's solution, but not the syntax that it requires. Both his and ~unutbu's answers inspired the following solution, which is closerto the spirit of what I was looking for:
编辑:我喜欢Alex Martelli 解决方案的简单性,但不喜欢它所需的语法。他和~unutbu 的回答都激发了以下解决方案,这更接近于我正在寻找的精神:
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
Now, I get:
现在,我得到:
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
#
I prefer this solution because:
我更喜欢这个解决方案,因为:
- The members get declared inline instead of after the fact, as with
type(X).foo = ...
- The members' values are set in the actual class's code as opposed to in the metaclass's code.
- 成员被声明为内联而不是事后声明,就像
type(X).foo = ...
- 成员的值在实际类的代码中设置,而不是在元类的代码中。
It's still not ideal because:
它仍然不理想,因为:
- I have to set the
__metaclass__
in order forconst_value
objects to be interpreted correctly. - The
const_value
s don't "behave" like the plain values. For example, I couldn't use it as a default value for a parameter to a method in the class.
- 我必须设置
__metaclass__
以便const_value
正确解释对象。 - 该
const_value
■不要“行为”之类的普通值。例如,我不能将它用作类中方法的参数的默认值。
回答by Alex Martelli
The existing solutions are a bit complex -- what about just ensuring that each class in a certain group has a unique metaclass, then setting a normal read-only property on the 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 much simpler, because it's based on nothing more than the fact that when you get an instance's attribute descriptors are looked up on the class (so of course when you get a class's attribute descriptors are looked on the metaclass), and making class/metaclass unique isn't terribly hard.
这真的要简单得多,因为它基于这样一个事实:当你得到一个实例的属性描述符时,会在类上查找(当然,当你得到一个类的属性描述符时,会在元类上查找),并使类/metaclass unique 并不是很难。
Oh, and of course:
哦,当然:
>>> X.foo = 67
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
just to confirm it IS indeed read-only!
只是为了确认它确实是只读的!
回答by unutbu
The ActiveState solutionthat Pynt references makes instances of ROClass have read-only attributes. Your question seems to ask if the class itself can have read-only attributes.
Pynt 引用的ActiveState 解决方案使 ROClass 的实例具有只读属性。您的问题似乎是问类本身是否可以具有只读属性。
Here is one way, based on Raymond Hettinger's comment:
这是一种方法,基于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
The idea is this: Consider first Raymond Hettinger's solution:
这个想法是这样的:首先考虑 Raymond Hettinger 的解决方案:
class Bar(object):
CLASS_PROPERTY = property(lambda self: 1)
bar=Bar()
bar.CLASS_PROPERTY=2
It shows a relatively simple way to give bar a read-only property.
它展示了一种相对简单的方法来给 bar 一个只读属性。
Notice that you have to add the CLASS_PROPERTY = property(lambda self: 1)
line to the definition of the class of bar, not to bar itself.
请注意,您必须将该CLASS_PROPERTY = property(lambda self: 1)
行添加到 bar 类的定义中,而不是 bar 本身。
So, if you want the class Foo
to have a read-only property, then the parent class of Foo
has to have CLASS_PROPERTY = property(lambda self: 1)
defined.
因此,如果您希望该类Foo
具有只读属性,则Foo
必须CLASS_PROPERTY = property(lambda self: 1)
定义其父类。
The parent class of a class is a metaclass. Hence we define ROType as the metaclass:
一个类的父类是一个元类。因此我们将 ROType 定义为元类:
class ROType(type):
CLASS_PROPERTY = readonly(1)
Then we make Foo's parent class be ROType:
然后我们将 Foo 的父类设为 ROType:
class Foo(object):
__metaclass__=ROType
回答by Isaiah
Found this on ActiveState:
在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 a read-only attribute (t.a = 2
) python will raise an AttributeError
.
请注意,如果您尝试设置只读属性 ( t.a = 2
),python 将引发AttributeError
.