我有许多不同的小类,每个类都有几个字段,例如:
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的——还有很多样板代码要写(特别是如果我有多个字段要使其成为只读的话)。然而,它确实起到了作用,而且很容易看出原因。
使用^{
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__
实现。或者用一些调味品?在任何情况下,我都需要决定在客户机试图为只读字段赋值时如何操作。我想应该有个例外-但是哪一个?
使用实用程序函数自动定义属性(以及可选的getter)。这和(1)基本上是一样的,只是我没有把getter写得很清楚,而是做了如下的事情
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__
定义这一事实。我希望有一种方法来“注释”字段,以便自动发生这种情况。有人有更好的主意吗?
不管怎样,我要唱Python2.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)
。在我看来,这很整洁-有人能看出它的缺点吗?
我将使用^{} 作为装饰器来管理
name
的getter(请参阅文档中类Parrot
的示例)。例如,使用类似于:如果没有为
name
属性定义setter(在函数周围使用decoratorx.setter
),则在尝试重置name
时,将抛出AttributeError
。注意:必须使用Python的新样式类(即在Python 2.6中,必须从根据@SvenMarnach,情况并非如此。object
继承)才能使属性正常工作。根据克里斯的回答,但可以说更像是Python:
如果试图修改属性,它将引发一个
AttributeError
。UPDATE:关于您更新的答案,我看到的(小)问题是,每次创建实例时,您都在修改类中属性的定义。我不认为这是个好主意。所以我把
ro_property
调用放在__init__
函数之外怎么办?以下内容:
班主任真是太花哨了!
正如在其他答案中指出的,使用属性是只读属性的方法。Chris' answer中的解决方案是最干净的:它直接、简单地使用了内置的
property()
。熟悉Python的每个人都会认识到这个模式,并且没有发生特定领域的巫毒。如果您不喜欢,每个属性都需要三条线来定义,下面是另一个直截了当的方法:
一般来说,我不喜欢定义特定于域的函数来做一些可以用标准工具轻松完成的事情。如果你不需要先习惯所有特定于项目的东西,那么阅读代码就容易多了。
相关问题 更多 >
编程相关推荐