在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 特殊方法 (1)
標準庫 (4)
如何成為 Python 高手
標準庫 (6)
標準庫 (3)
類(2)
Pandas 使用 (2)
xml
用 tornado 做網站 (5)
文件(1)
練習
列表(3)
從小工到專家
除法
錯誤和異常 (2)
函數(shù)(1)
用 tornado 做網站 (7)
為做網站而準備
函數(shù)練習
標準庫 (8)
Pandas 使用 (1)
回顧 list 和 str
字典(1)
用 tornado 做網站 (3)
字符串(1)
函數(shù)(2)
寫一個簡單的程序
將數(shù)據存入文件
語句(5)
SQLite 數(shù)據庫
集成開發(fā)環(huán)境(IDE)
集合(1)
類(1)
用 tornado 做網站 (6)
用 tornado 做網站 (2)
自省
語句(4)
錯誤和異常 (1)
用 tornado 做網站 (4)
集合(2)
列表(1)
標準庫 (1)
生成器
mysql 數(shù)據庫 (1)
第三方庫
實戰(zhàn)
運算符
類(3)
字典(2)
語句(1)
數(shù)和四則運算
語句(2)
文件(2)
MySQL 數(shù)據庫 (2)
電子表格
迭代器
mongodb 數(shù)據庫 (1)
特殊方法 (2)
特殊方法 (1)
字符編碼
編寫模塊
用 tornado 做網站 (1)
標準庫 (5)
函數(shù)(4)
類(5)
字符串(2)
關于 Python 的故事
函數(shù)(3)
字符串(4)
處理股票數(shù)據
常用數(shù)學函數(shù)和運算優(yōu)先級
字符串(3)
為計算做準備
多態(tài)和封裝
類(4)
迭代
語句(3)
錯誤和異常 (3)
分析 Hello
Python 安裝
標準庫 (2)
列表(2)
元組

特殊方法 (1)

探究更多的類屬性,在一些初學者的教程中,一般很少見。我之所以要在這里也將這部分奉獻出來,就是因為本教程是“From Beginner to Master”。當然,不是學習了類的更多屬性就能達到 Master 水平,但是這是通往 Master 的一步,雖然在初級應用中,本節(jié)乃至于后面關于類的屬性用的不很多,但是,這一步邁出去,你就會在實踐中有一個印象,以后需要用到了,知道有這一步,會對項目有幫助的。俗話說“藝不壓身”。

__dict__

前面已經學習過有關類屬性和實例屬性的內容,并且做了區(qū)分,如果忘記了可以回頭參閱《類(3)》中的“類屬性和實例屬性”部分。有一個結論,是一定要熟悉的,那就是可以通過 object.attribute 的方式訪問對象的屬性。

如果接著那部分內容,讀者是否思考過一個問題:類或者實例屬性,在 Python 中是怎么存儲的?或者為什么修改或者增加、刪除屬性,我們能不能控制這些屬性?

>>> class A(object):
...     pass
...

>>> a = A()
>>> dir(a)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> dir(A)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

dir() 來查看一下,發(fā)現(xiàn)不管是類還是實例,都有很多屬性,這在前面已經反復出現(xiàn),有點見怪不怪了。不過,這里我們要看一個屬性:__dict__,因為它是一個保存秘密的東西:對象的屬性。

>>> class Spring(object):
...     season = "the spring of class"
... 

>>> Spring.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Spring' objects>, 
'season': 'the spring of class', 
'__module__': '__main__', 
'__weakref__': <attribute '__weakref__' of 'Spring' objects>, 
'__doc__': None})

為了便于觀察,我將上面的顯示結果進行了換行,每個鍵值對一行。

對于類 Spring 的__dict__屬性,可以發(fā)現(xiàn),有一個鍵'season',這就是這個類的屬性;其值就是類屬性的數(shù)據。

>>> Spring.__dict__['season']
'the spring of class'
>>> Spring.season
'the spring of class'

用這兩種方式都能得到類屬性的值?;蛘哒f Spring.__dict__['season'] 就是訪問類屬性。下面將這個類實例化,再看看它的實例屬性:

>>> s = Spring()
>>> s.__dict__
{}

實例屬性的__dict__是空的。有點奇怪?不奇怪,接著看:

>>> s.season
'the spring of class'

這個其實是指向了類屬性中的 Spring.season,至此,我們其實還沒有建立任何實例屬性呢。下面就建立一個實例屬性:

>>> s.season = "the spring of instance"
>>> s.__dict__
{'season': 'the spring of instance'}

這樣,實例屬性里面就不空了。這時候建立的實例屬性和上面的那個 s.season 只不過重名,并且把它“遮蓋”了。這句好是不是熟悉?因為在講述“實例屬性”和“類屬性”的時候就提到了?,F(xiàn)在讀者肯定理解更深入了。

>>> s.__dict__['season']
'the spring of instance'
>>> s.season
'the spring of instance'

此時,那個類屬性如何?我們看看:

>>> Spring.__dict__['season']
'the spring of class'
>>> Spring.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Spring' objects>, 'season': 'the spring of class', '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Spring' objects>, '__doc__': None})
>>> Spring.season
'the spring of class'

Spring 的類屬性沒有受到實例屬性的影響。

按照前面的講述類屬性和實例熟悉的操作,如果這時候將前面的實例屬性刪除,會不會回到實例屬性s.__dict__為空呢?

>>> del s.season
>>> s.__dict__
{}
>>> s.season
'the spring of class'

果然打回原形。

當然,你可以定義其它名稱的實例屬性,它一樣被存儲到__dict__屬性里面:

>>> s.lang = "python"
>>> s.__dict__
{'lang': 'python'}
>>> s.__dict__['lang']
'python'

誠然,這樣做僅僅是更改了實例的__dict__內容,對 Spring.__dict__無任何影響,也就是說通過 Spring.lang 或者 Spring.__dict__['lang'] 是得不到上述結果的。

>>> Spring.lang
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Spring' has no attribute 'lang'

>>> Spring.__dict__['lang']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'lang'

那么,如果這樣操作,會怎樣呢?

>>> Spring.flower = "peach"
>>> Spring.__dict__
dict_proxy({'__module__': '__main__', 
'flower': 'peach', 
'season': 'the spring of class', 
'__dict__': <attribute '__dict__' of 'Spring' objects>, '__weakref__': <attribute '__weakref__' of 'Spring' objects>, '__doc__': None})
>>> Spring.__dict__['flower']
'peach'

在類的__dict__被更改了,類屬性中增加了一個'flower'屬性。但是,實例的__dict__中如何?

>>> s.__dict__
{'lang': 'python'}

沒有被修改。我也是這么想的,哈哈。你此前這這么覺得嗎?然而,還能這樣:

>>> s.flower
'peach'

這個讀者是否能解釋?其實又回到了前面第一個出現(xiàn) s.season 上面了。

通過上面探討,是不是基本理解了實例和類的__dict__,并且也看到了屬性的變化特點。特別是,這些屬性都是可以動態(tài)變化的,就是你可以隨時修改和增刪。

屬性如此,方法呢?下面就看看方法(類中的函數(shù))。

>>> class Spring(object):
...     def tree(self, x):
...         self.x = x
...         return self.x
... 
>>> Spring.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Spring' objects>, 
'__weakref__': <attribute '__weakref__' of 'Spring' objects>, 
'__module__': '__main__', 
'tree': <function tree at 0xb748fdf4>, 
'__doc__': None})

>>> Spring.__dict__['tree']
<function tree at 0xb748fdf4>

結果跟前面討論屬性差不多,方法 tree 也在__dict__里面呢。

>>> t = Spring()
>>> t.__dict__
{}

又跟前面一樣。雖然建立了實例,但是在實例的__dict__中沒有方法。接下來,執(zhí)行:

>>> t.tree("xiangzhangshu")
'xiangzhangshu'

類(3)中有一部分內容闡述“數(shù)據流轉”,其中有一張圖,其中非常明確顯示出,當用上面方式執(zhí)行方法的時候,實例 tself 建立了對應關系,兩者是一個外一個內。在方法中 self.x = x,將 x 的值給了 self.x,也就是實例應該擁有了這么一個屬性。

>>> t.__dict__
{'x': 'xiangzhangshu'}

果然如此。這也印證了實例 tself 的關系,即實例方法(t.tree('xiangzhangshu'))的第一個參數(shù)(self,但沒有寫出來)綁定實例 t,透過 self.x 來設定值,即給 t.__dict__添加屬性值。

換一個角度:

>>> class Spring(object):
...     def tree(self, x):
...         return x
...

這回方法中沒有將 x 賦值給 self 的屬性,而是直接 return,結果是:

>>> s = Spring()
>>> s.tree("liushu")
'liushu'
>>> s.__dict__
{}

是不是理解更深入了?

現(xiàn)在需要對 Python 中一個觀點:“一切皆對象”,再深入領悟。以上不管是類還是的實例的屬性和方法,都是符合 object.attribute 格式,并且屬性類似。

當你看到這里的時候,要么明白了類和實例的__dict__的特點,要么就糊涂了。糊涂也不要緊,再將上面的重復一遍,特別是自己要敲一敲有關代碼。(建議一個最好的方法:用兩個顯示器,一個顯示器看本教程,另外一個顯示器敲代碼。事半功倍的效果。)

需要說明,我們對__dict__的探討還留有一個尾巴:屬性搜索路徑。這個留在后面講述。

不管是類還是實例,其屬性都能隨意增加。這點在有時候不是一件好事情,或許在某些時候你不希望別人增加屬性。有辦法嗎?當然有,請繼續(xù)學習。

__slots__

首先聲明,__slots__能夠限制屬性的定義,但是這不是它存在終極目標,它存在的終極目標更應該是一個在編程中非常重要的方面:優(yōu)化內存使用。

>>> class Spring(object):
...     __slots__ = ("tree", "flower")
... 
>>> dir(Spring)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'flower', 'tree']

仔細看看 dir() 的結果,還有__dict__屬性嗎?沒有了,的確沒有了。也就是說__slots____dict__擠出去了,它進入了類的屬性。

>>> Spring.__slots__
('tree', 'flower')

這里可以看出,類 Spring 有且僅有兩個屬性。

>>> t = Spring()
>>> t.__slots__
('tree', 'flower')

實例化之后,實例的__slots__與類的完全一樣,這跟前面的__dict__大不一樣了。

>>> Spring.tree = "liushu"

通過類,先賦予一個屬性值。然后,檢驗一下實例能否修改這個屬性:

>>> t.tree = "guangyulan"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Spring' object attribute 'tree' is read-only

看來,我們的意圖不能達成,報錯信息中顯示,tree 這個屬性是只讀的,不能修改了。

>>> t.tree
'liushu'

因為前面已經通過類給這個屬性賦值了。不能用實例屬性來修改。只能:

>>> Spring.tree = "guangyulan"
>>> t.tree
'guangyulan'

用類屬性修改。但是對于沒有用類屬性賦值的,可以通過實例屬性:

>>> t.flower = "haitanghua"
>>> t.flower
'haitanghua'

但此時:

>>> Spring.flower
<member 'flower' of 'Spring' objects>

實例屬性的值并沒有傳回到類屬性,你也可以理解為新建立了一個同名的實例屬性。如果再給類屬性賦值,那么就會這樣了:

>>> Spring.flower = "ziteng"
>>> t.flower
'ziteng'

當然,此時在給 t.flower 重新賦值,就會爆出跟前面一樣的錯誤了。

>>> t.water = "green"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Spring' object has no attribute 'water'

這里試圖給實例新增一個屬性,也失敗了。

看來__slots__已經把實例屬性牢牢地管控了起來,但更本質是的是優(yōu)化了內存。誠然,這種優(yōu)化會在大量的實例時候顯出效果。


總目錄   |   上節(jié):多態(tài)和封裝   |   下節(jié):特殊方法(2)

如果你認為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。

上一篇:錯誤和異常 (3)下一篇:字符串(2)