Я не думаю, что это вполне возможно, за исключением использования кортежа или именованного кортежа.Независимо от того, что, если вы переопределите __setattr__()
, пользователь всегда может обойти его, вызвав object.__setattr__()
напрямую.Любое решение, которое зависит от __setattr__
, гарантированно не будет работать.
Ниже приводится информация о ближайшем, которое вы можете получить без использования какого-либо кортежа:
class Immutable:
__slots__ = ['a', 'b']
def __init__(self, a, b):
object.__setattr__(self, 'a', a)
object.__setattr__(self, 'b', b)
def __setattr__(self, *ignored):
raise NotImplementedError
__delattr__ = __setattr__
, но оно ломается, если выпопробуй достаточно:
>>> t = Immutable(1, 2)
>>> t.a
1
>>> object.__setattr__(t, 'a', 2)
>>> t.a
2
, но использование Свеном namedtuple
действительно неизменно.
Обновление
Поскольку вопрос был обновлен доСпросите, как сделать это правильно в C, вот мой ответ о том, как сделать это правильно в Cython:
Первый immutable.pyx
:
cdef class Immutable:
cdef object _a, _b
def __init__(self, a, b):
self._a = a
self._b = b
property a:
def __get__(self):
return self._a
property b:
def __get__(self):
return self._b
def __repr__(self):
return "<Immutable {0}, {1}>".format(self.a, self.b)
и setup.py
для его компиляции (используя команду setup.py build_ext --inplace
:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("immutable", ["immutable.pyx"])]
setup(
name = 'Immutable object',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
Затем, чтобы попробовать это:
>>> from immutable import Immutable
>>> p = Immutable(2, 3)
>>> p
<Immutable 2, 3>
>>> p.a = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: attribute 'a' of 'immutable.Immutable' objects is not writable
>>> object.__setattr__(p, 'a', 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: attribute 'a' of 'immutable.Immutable' objects is not writable
>>> p.a, p.b
(2, 3)
>>>