2017-06-16 80 views
2

我有一個類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. 

回答

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 

編輯。 作爲另一個答覆中提到,一個namedtuple是這樣做的自然的方式,但因爲你正在做施工過程中一些計算,使用類方法作爲一個可選的構造:

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 
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

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