python __slots__ .


python新模式的class,即從object繼承下來的類有一個變量是__slots__,slots的作用是阻止在實例化類時為實例分配dict,默認情況下每個類都會有一個dict,通過__dict__訪問,這個dict維護了這個實例的所有屬性,舉例如下
class base(object):
    v = 1
    def __init__(self):
          pass

b = base()
print b.__dict__
b.x = 2                     //可以增加新的變量
print b.__dict__
運行:
{}
{'x':2}
可見:實例的dict只保持實例的變量,對於類的屬性是不保存的,類的屬性包括變量和函數。由於每次實例化一個類都要分配一個新的dict,因此存在空間的浪費,因此有了slots,當定義了slots后,slots中定義的變量變成了類的描述符,相當於java,c++中的成員變量聲明,類的實例只能擁有這些個變量,而不在有dict, 因此也就不能在增加新的變量
class base(object):
   __slots__ = ('y')
    v = 1
    def __init__(self):
          pass

b = base()
print b.__dict__
b.x = 2              //error,不能增加新的變量 ( 任何試圖創建一個其名不在__slots__中的名字的實例屬性都將導致AttributeError異常)
print b.__dict__

注意,如果類的成員變量與slots中的變量同名,
class base(object):
    __slots=('y',)
   y = 2
    v = 1
    def __init__(self):
          pass

b = base()
print b.__dict__
b.x = 2
b.y = 3 //read only
print b.__dict__

目前的實現是該變量被設置為readonly!!!

Notes on using __slots__

  • Without a __dict__ variable, instances cannot be assigned new variables not listed in the __slots__ definition. Attempts to assign to an unlisted variable name raise an AttributeError. If dynamic assignment of new variables is desired, then add '__dict__' to the sequence of strings in the __slots__ declaration. (Changed in Python version 2.3)
  • Without a __weakref__ variable for each instance, classes defining __slots__ do not support weak references to its instances. If weak reference support is needed, then add '__weakref__' to the sequence of strings in the __slots__ declaration. (Changed in Python version 2.3)
  • __slots__ are implemented at the class level by creating descriptors ( 3.4.2.2) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __slots__; otherwise, the class attribute would overwrite the descriptor assignment.
  • If a class defines a slot also defined in a base class, the instance variable defined by the base class slot is inaccessible (except by retrieving its descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this.
  • The action of a __slots__ declaration is limited to the class where it is defined. As a result, subclasses will have a __dict__ unless they also define __slots__.
  • __slots__ do not work for classes derived from "variable-length" built-in types such as long, str and tuple.
  • Any non-string iterable may be assigned to __slots__. Mappings may also be used; however, in the future, special meaning may be assigned to the values corresponding to each key.

 

另外:

 由於在Python中不支持private這樣的私有化修飾符,所以如果想把一個類屬性置為私有的話,方法就是在屬性名前加上雙下划線__,這樣在編譯后,就可以起到保護私有屬性的作用

    例如:

    

Python代碼 復制代碼  收藏代碼
  1. 假如有個類Numstr有一個self.num屬性   
  2.     在加上雙下划線后變成self.__num后,經過編譯就形成了self.__Numstr__num了,可以有效的保護私有屬性,  
假如有個類Numstr有一個self.num屬性
    在加上雙下划線后變成self.__num后,經過編譯就形成了self.__Numstr__num了,可以有效的保護私有屬性,
Python代碼 復制代碼  收藏代碼
  1. 但並非無懈可擊,這只能算是一種保護機制  
但並非無懈可擊,這只能算是一種保護機制

 

  同時在Python中提供了限制用戶創建並未在類中定義的屬性,方法是在類的定義后跟一個__slots__屬性,它是一個元組,包括了當前能訪問到的屬性。例如:

   

Python代碼 復制代碼  收藏代碼
  1. class test(object):   
  2.     __slots__=('foo');       //可以訪問foo
  3.     foo=1.3;   
  4.        
  5. a=test();   
  6. print a.foo;   
  7. a.bar=15  
  8. print a.bar;   
  9.   
  10. 輸出:  
class test(object):
    __slots__=('foo');    
    foo=1.3;
    
a=test();
print a.foo;
a.bar=15
print a.bar;

輸出:
Python代碼 復制代碼  收藏代碼
  1. 1.3  
  2. Traceback (most recent call last):   
  3.   File "D:\pythonEclipse\PythonStudy\src\Unit13\TestSlots.py", line 7in <module>   
  4.     a.bar=15  
  5. AttributeError: 'test' object has no attribute 'bar'  

另外:

Python 是一門動態語言,可以在運行過程中,修改對象的屬性和增刪方法。任何類的實例對象包含一個字典__dict__, Python通過這個字典將任意屬性綁定到對象上。有時候我們只想使用固定的對象,而不想任意綁定對象,這時候我們可以定義一個屬性名稱集合,只有在這個集合里的名稱才可以綁定。__slots__就是完成這個功能的。

test code

1 # !/usr/bin/env python
2 # _*_ coding:utf-8 _*_
3
4 class test_slot(object):
5 __slots__ = " width " , " height "
6
7 def width(self):
8 print " width "
9
10
11 class test(object):
12  def amethod(self):
13  print " amethod "

ipython執行代碼導入

In [ 1 ]: from test import *
In [
2 ]: dir(test_slot)
Out[
2 ]:
[
' __class__ ' ,
' __slots__ ' ,
' __str__ ' ,
' height ' ,
' width ' ]

In [
3 ]: dir(test)
Out[
3 ]:
[
' __class__ ' ,
' __weakref__ ' ,
' amethod ' ]

可以看到 test_slot 類結構里面已經有height和width屬性了。

下面我們繼續查看兩個實例對象結構里都有什么吧

In [ 4 ]: s = test_slot()
In [
5 ]: t = test()

In [
11 ]: dir(s)
Out[
11 ]:
[
' __class__ ' ,
' __delattr__ ' ,
' __doc__ ' ,
' __slots__ ' ,
' height ' ,
' width ' ]

In [
12 ]: dir(t)
Out[
12 ]:
[
' __class__ ' ,
' __delattr__ ' ,
' __dict__ ' ,
' __doc__ ' ,
' amethod ' ]

看到了吧, test_slot 的實例s 沒有字典__dict__,多了__slots__屬性,這樣就不能任意綁定屬性,只能綁定__slots__屬性名稱集合里的同名屬性了。

我們來測試一把,先給兩個實例的賦__slots__里面有的 height 屬性,當然對t來說是新加屬性。

In [7]: s.height = 1
In [8]: t.height = 0

賦值都沒有問題。

下面再試一下不在__slots__里的屬性名.

In [ 9 ]: s.abeen = " abeen " // 和預期的一樣,失敗了。
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)

/ home / abeen / learn_test / test /< ipython console > in < module > ()

AttributeError:
' test_slot ' object has no attribute ' abeen '

In [
10 ]: t.abeen = " abeen " // 正常運行


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM