2017-08-04 169 views
0

我要尋找在python的方式來建立Python類是:不可改變的屬性

  • 二傳手分配前檢查值的類型
  • 不可能增加新的類屬性

暫時我發現,這兩項裝飾:

 

    def getter_setter_gen(name, type_): 
     def getter(self): 
      return getattr(self, "__" + name) 
     def setter(self, value): 
      print "setter", value 
      if not isinstance(value, type_): 
       raise TypeError("%s attribute must be set to an instance of %s" % (name, type_)) 
      setattr(self, "__" + name, value) 
     return property(getter, setter) 


    def auto_attr_check(cls): 
     new_dct = {} 
     print "auto_attr_check", cls.__dict__.items() 
     for key, value in cls.__dict__.items(): 
      if isinstance(value, type): 
       value = getter_setter_gen(key, value) 
      new_dct[key] = value 
     # Creates a new class, using the modified dictionary as the class dict: 
     n = type(cls)(cls.__name__, cls.__bases__, new_dct) 
     return n 

 

    def froze_it(cls): 
     def frozensetattr(self, key, value): 
      print key 
      key = ''+key 
      print(dir(self)) 
      print key 
      if not hasattr(self, key): 
       raise TypeError("Class {} is frozen. Cannot set {} = {}" 
        .format(cls.__name__, key, value)) 
      else: 
       object.__setattr__(self, key, value) 
     cls.__setattr__ = frozensetattr 
     return cls 

但我有很多麻煩加入這兩種方法。 你能幫我嗎?你有想法嗎? 非常感謝

回答

1

您遇到的問題是,你的property使用setattr設置你的屬性值,但你以這樣一種方式,它永遠不能成功覆蓋__setattr__hasattr檢查對於主屬性名稱和屬性下面的實際屬性的下劃線前綴名稱(如果setter代碼可以得到那麼多)將會失敗。

我建議兩個補充修復。首先,將hasattr檢查更改一點。如果失敗了,它也應該檢查類字典爲屬性對象:

def frozensetattr(self, key, value): 
     if not hasattr(self, key) and type(cls.__dict__.get(key)) is not property: 
      raise TypeError("Class {} is frozen. Cannot set {} = {}" 
       .format(cls.__name__, key, value)) 
     else: 
      object.__setattr__(self, key, value) 

第二解決方法是在setter功能,它應該繞過底層屬性__setattr__方法:

def setter(self, value): 
     print "setter", value 
     if not isinstance(value, type_): 
      raise TypeError("%s attribute must be set to an instance of %s" % (name, type_)) 
     object.__setattr__(self, "__" + name, value) 

最後一點:由property創建的屬性名稱上的雙下劃線前綴不會引起名稱混亂,我懷疑它是你的意圖。名稱修改只發生在編譯時。當一個方法包含名稱如__bar時,名稱會被編譯器轉換爲_NameOfTheClass__bar(其中NameOfTheClass是該方法在其中定義的類的名稱)。

在運行時,代碼的行爲完全就像直接在源代碼中寫入的名稱一樣。這意味着__setattr__和朋友不會以任何特殊的方式處理重名的名稱(或者雙下劃線前綴名,如果它們被編寫爲常規變量名而不是字符串,則會被編譯器破壞)。所以沒有簡單的方法來對動態創建的變量進行名稱修改。

如果你只是想讓你的名字被非正式地標記爲私人的(也就是說,它們不是公共API的一部分),你應該使用一個前導下劃線。