我有一个班级DifferentialExtension
:
class DifferentialExtension(object):
__slots__ = ('f', 'x', 'D', 'T')
def __init__(self, f=None, x=None):
/*
# some code that builds up list 'self.D'
*/
self.D = tuple(self.D)
return None
我要使类“不可变”,即不允许使用DifferentialExtension
创建的对象更改属性“D”(在__init__
完成后),这些属性都不会被分配给一个新的对象。 D
不一定是list
,最后返回时可以是tuple
。
In [1]: DE = DifferentialExtension(log(x), x)
In [2]: DE.D
Out[2]: ((Poly(1, x, domain='ZZ'), Poly(1/x, t0, domain='ZZ(x)'))
In [3]: DE.D = (1, 5, 5) # raises Error.
答案 0 :(得分:3)
一般来说,在Python中,你必须假设使用你的课程的人并没有试图做一些恶毒的事情。因此,如果他真的想要改变D
的值,他可能有充分的理由。因此,您可能不希望无法更改D
,因为这不是pythonic。但是,您可能希望帮助用户不要意外更改D
。最好使用只读属性,如:
class DifferentialExtension(object):
def __init__(self, f=None, x=None):
self._D = 'immutable value'
return None
@property
def D(self):
return self._D
运行此命令:
>>> d = DifferentialExtension()
>>> d.D = 'mutate'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
如果用户确实想要更改该值,他可以直接访问self._D
但是你必须假设他知道自己在做什么,因为他正在弄乱一个您的内部强调变量。
答案 1 :(得分:1)
这样的东西?
class DifferentialExtension(object):
_frozen = set()
__slots__ = ('f', 'x', 'D', 'T')
def __init__(self, f=None, x=None):
self.D = 'something'
self.D = tuple(self.D)
self._frozen.add(id(self))
def __setattr__(self, attr, value):
if id(self) in self._frozen:
raise TypeError('object is frozen')
object.__setattr__(self, attr, value)
<强>测试强>:
In [29]: a = DifferentialExtension('eh', 'oh')
In [30]: a.D
Out[30]: ('s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g')
In [31]: a.D = 'something else'
...
TypeError: object is frozen
编辑。 正如另一个答案中所提到的,命名元组是执行此操作的自然方式,但由于您在构造期间进行了一些计算,因此使用 classmethod 作为替代构造函数:
class DifferentialExtension(namedtuple('DifferentialExtension', 'f, x, D, T')):
@classmethod
def build_me(cls, f=None, x=None):
# a bunch of code that works on D and sets D and T (if you need T)
T = 'something T'
D = 'something' ##D = tuple(D) works
return cls(f, x, D, T)
测试namedtuple :
In [41]: DE = DifferentialExtension.build_me(f='some f value', x='some x value')
In [42]: DE.D
Out[42]: 'something'
In [43]: DE.D = 'some other thing'
...
AttributeError: can't set attribute
答案 2 :(得分:1)
使用namedtuple
作为不可变对象的基础。如果您愿意,可以根据自己的需要扩展它们。
from collections import namedtuple
class DifferentialExtension(namedtuple('DifferentialExtension', 'f x')):
def another_method(self):
print self.x
x = DifferentialExtension(1, 2)
x.f = 2.2
# AttributeError: can't set attribute