2017-12-27 141 views
0

我知道__slots__做什麼,它應該用於什麼。__slot__描述符如何在python中工作?

但是,我還沒有找到一個全面的答案,如何使用__slots__創建的member描述符的下層機制的作品。

對象級別的值在哪裏實際存儲?

有沒有辦法改變這些值,而不直接屬性訪問描述符?
(例如:上課時C__dict__你可以做C.__dict__['key']代替C.key

通過創建類似的類級別的描述可以在一個「擴展」 __slots__對象定義的不變性?並進一步闡述這一點;可以使用元類構建一個不可變的對象,但是通過手動創建所述描述符來明確定義__slots__

回答

0

__slot__屬性被分配在該對象的本機存儲器的表示,和相關聯的訪問然後實際的類描述符使用本地C方法CPython的設置和檢索歸因於每個時隙中的Python對象的參考屬性上類實例作爲C結構。

描述符的插槽,在Python名爲member_descriptor呈現在這裏定義:https://github.com/python/cpython/blob/master/Objects/descrobject.c

您不能執行或以任何方式提高從純Python代碼,這些描述符不使用ctypes的與本地代碼進行交互。

有可能通過做類似

class A: 
    __slots__ = "a" 

member_descriptor = type(A.a) 

去他們的類型,那麼可以supose將有可能繼承它,並寫出推導__get____set__方法,可以做到chekings和這樣的 - 但不幸的是,它不能作爲基類。

但是,可以編寫其他並行描述符,這些描述符可以調用本地描述符來實際更改代碼。 通過使用元類,可以在創建類時重命名傳入的__slots__並將它們的訪問包裝在可執行額外檢查的自定義描述符中 - 甚至可以從「dir」中隱藏。

所以,對一個天真的類型檢查插槽變種元類,一個人可能

class TypedSlot: 
    def __init__(self, name, type_): 
     self.name = name 
     self.type = type_ 

    def __get__(self, instance, owner): 
     if not instance: 
      return self 
     return getattr(instance, "_" + self.name) 

    def __set__(self, instance, value): 
     if not isinstance(value, self.type): 
      raise TypeError 
     setattr(instance, "_" + self.name, value) 


class M(type): 
    def __new__(metacls, name, bases, namespace): 
     new_slots = [] 
     for key, type_ in namespace.get("__slots__", {}).items(): 
      namespace[key] = TypedSlot(key, type_) 
      new_slots.append("_" + key) 
     namespace["__slots__"] = new_slots 
     return super().__new__(metacls, name, bases, namespace) 

    def __dir__(cls): 
     return [name for name in super().__dir__() if name not in cls.__slots__]