我应该如何公开Python类中的只读字段?
我有许多不同的小类,每个小类都有几个字段,例如:
class Article:
def __init__(self, name, available):
self.name = name
self.available = available
将name
字段设为只读的最简单和/或最惯用的方法是什么,以便
a = Article("Pineapple", True)
a.name = "Banana" # <-- should not be possible
不可能了吗?
到目前为止,这是我考虑的内容:
- 使用吸气剂(嗯!)。
class Article: def __init__(self, name, available): self._name = name self.available = available def name(self): return self._name
丑陋的,非pythonic的-以及很多要编写的样板代码(特别是如果我有多个要设置为只读的字段)。但是,它确实可以胜任工作,而且很容易明白为什么会这样。
- 用途
__setattr__
:class Article: def __init__(self, name, available): self.name = name self.available = available def __setattr__(self, name, value): if name == "name": raise Exception("%s property is read-only" % name) self.__dict__[name] = value
在调用方看来很漂亮,这似乎是完成工作的惯用方式-
但不幸的是,我有很多类,只有几个字段可以使每个字段只读。因此,我需要__setattr__
为所有这些添加实现。还是使用某种mixin?无论如何,如果客户端尝试将值分配给只读字段,我将需要下定决心。我猜会产生一些例外-
但是哪个呢?
- 使用实用程序功能自动定义属性(以及可选的吸气剂)。这与(1)基本上是相同的想法,除了我没有明确地写出吸气剂而是做类似的事情
class Article: def __init__(self, name, available): # This function would somehow give a '_name' field to self # and a 'name()' getter to the 'Article' class object (if # necessary); the getter simply returns self._name defineField(self, "name") self.available = available
缺点是我什至不知道这是否可能(或如何实现),因为我不熟悉Python中的运行时代码生成。:-)
到目前为止,(2)对我来说似乎最有前途,除了我需要__setattr__
为所有班级定义之外。我希望有一种“注释”字段的方法,以便自动进行。有人有更好的主意吗?
对于它的价值,我要使用Python 2.6。
更新: 感谢所有有趣的回复!现在,我有了这个:
def ro_property(o, name, value):
setattr(o.__class__, name, property(lambda o: o.__dict__["_" + name]))
setattr(o, "_" + name, value)
class Article(object):
def __init__(self, name, available):
ro_property(self, "name", name)
self.available = available
这似乎工作得很好。对原始课程的唯一更改是
- 我需要继承
object
(我想这绝对不是一件愚蠢的事情) - 我需要更改
self._name = name
为ro_property(self, "name", name)
。
这对我来说看起来很整洁-有人可以看到它的缺点吗?
-
我将
property
用作装饰器来管理您的getter
name
(请参阅Parrot
文档中该类的示例)。使用例如:class Article(object): def __init__(self, name, available): self._name = name self.available = available @property def name(self): return self._name
如果未定义
name
属性的设置器(x.setter
在函数周围使用装饰器),则AttributeError
在尝试重置时会抛出name
。注意 :必须使用Python的新型类(即,在python@SvenMarnach则不是这种情况。
2.6中必须从继承object
),属性才能正常工作。