У меня есть много разных небольших классов, которые иметь несколько полей каждый, например this:
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
Уродливый, не-питоновский -и много стандартного кода для написания (, особенно если у меня есть несколько полей, которые нужно сделать -только для чтения). Тем не менее, он выполняет свою работу, и легко понять, почему это так.
Использование__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__
ко всем из них. Или использовать какой-то миксин, может быть? В любом случае мне нужно решить, как себя вести, если клиент попытается присвоить значение полю -только для чтения. Дайте какое-то исключение, я думаю -, но какое?
Используйте служебную функцию для автоматического определения свойств (и, возможно, геттеров). В основном это та же идея, что и (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)
.На мой взгляд, это довольно неплохо -Кто-нибудь может увидеть в этом недостаток?