Способы сделать класс неизменным в Python
Я делаю некоторые распределенные вычисления, в которых несколько машин общаются в предположении, что все они имеют одинаковые версии различных классов. Таким образом, кажется, что это хороший дизайн, чтобы сделать эти классы неизменными; не в том смысле, что он должен помешать пользователю с плохими намерениями, просто неизменным, что он никогда не модифицируется случайно.
Как я могу это сделать? Например, как мне реализовать метакласс, который сделает класс неизменным после его определения?
>>> class A(object):
... __metaclass__ = ImmutableMetaclass
>>> A.something = SomethingElse # Don't want this
>>> a = A()
>>> a.something = Whatever # obviously, this is still perfectly fine.
Альтернативные методы также прекрасны, например, декоратор/функция, которая берет класс и возвращает неизменяемый класс.
Ответы
Ответ 1
Если старый трюк использования __slots__
не подходит вам, это или какой-либо его вариант может сделать:
просто напишите __setattr__
метод вашего метакласса, чтобы быть вашим стражем. В этом примере я запрещаю назначать новые атрибуты, но допускаю модификацию существующих:
def immutable_meta(name, bases, dct):
class Meta(type):
def __init__(cls, name, bases, dct):
type.__setattr__(cls,"attr",set(dct.keys()))
type.__init__(cls, name, bases, dct)
def __setattr__(cls, attr, value):
if attr not in cls.attr:
raise AttributeError ("Cannot assign attributes to this class")
return type.__setattr__(cls, attr, value)
return Meta(name, bases, dct)
class A:
__metaclass__ = immutable_meta
b = "test"
a = A()
a.c = 10 # this works
A.c = 20 # raises valueError
Ответ 2
Не тратьте время на неизменные занятия.
Есть вещи, которые вы можете сделать, которые далеки, намного проще, чем возиться с попыткой создания неизменяемого объекта.
Вот пять отдельных методов. Вы можете выбирать из них. Любой будет работать. Некоторые комбинации также будут работать.
- Документация
. Собственно, они этого не забудут. Дайте им кредит.
-
Unit test. Выделите ваши объекты приложения простым макетом, который обрабатывает __setattr__
в качестве исключения. Любое изменение состояния объекта является ошибкой в unit test. Это легко и не требует сложного программирования.
-
Переопределить __setattr__
, чтобы создать исключение при каждой попытке записи.
-
collections.namedtuple
. Они неизменяемы из коробки.
-
collections.Mapping
. Он неизменен, но вам нужно реализовать несколько методов, чтобы заставить его работать.
Ответ 3
Если вы не против повторного использования работы другого человека:
http://packages.python.org/pysistence/
Непрерывные постоянные (в функциональных, а не записывающих в десктоп смысле) структуры данных.
Даже если вы не используете их как есть, исходный код должен дать некоторое вдохновение. Например, их класс expando принимает в нем объект в конструкторе и возвращает неизменную версию.