Data model in python

來源:互聯網
上載者:User

今天,談談python中的資料模型,當然你可以不瞭解這些東西,照樣可以寫出漂亮的python代碼,但是“知其然知其所以然”是我的作風,總是不明白python的一些機制,心裡很不爽。結合python的doc和一篇文章,差不多明白了python的哲理。

我覺得有必要將python中的文檔的一些重要語句拿出來。

Objects are Python’s abstraction for data. All data in a Python program is represented by objects or by relations between objects.
Every object has an identity, a type and a value.

為什麼我這裡要強調這裡的對象,有對象以為著有一些屬性(函數也罷,變數也罷都是屬性)與之關聯,你操作一個對象,其實就是在和這些屬性打交道。

在這裡,我集中在python中的類,去弄明白python中的類究竟是怎麼完成其功能的.
A class has a namespace implemented by a dictionary object. Class attribute references are translated to lookups in this dictionary.

這句話很重要,一個類有其自己的namespace(命名空間),而且這個命名空間的實現本質上是一個字典。換句話說,你對一個類的操作其實就是在對這個“特殊”的字典進行操作,那麼怎麼去區分類的執行個體和類呢,其實在python中,類的執行個體也有一個字典,去記錄該執行個體的屬性。

view plaincopy to clipboardprint?
  1. class T(object):  
  2.     age = 21  
  3.   
  4. t = T()  
  5. t.name = "ilovebaiyang"  
  6.   
  7. print "dir(T):", dir(T)  
  8. print "dir(t):", dir(t)  

這個列印的結果是:

view plaincopy to clipboardprint?
  1. dir(T): ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age']  
  2.   
  3. dir(t): ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']  

其中有些屬性是從object上繼承來的,比如__doc__, __setattr__,__dict__等等,其中值得注意的是自訂屬性,age和name,他們分別存在於類T中和類T的執行個體t中,那麼為什麼在dir(t)中出現了age的屬性呢,原因是從它的類上複製過來的,而且如果我們列印他們的id,其實他們的id是一樣的。在這裡,我們出現了一個疑問,前面提到的命名空間的字典就是dir()函數產生的字典麼,看上去貌似是,因為它的確記錄了該對象的所有屬性,其實這個是錯誤的,原因我們就要回到dir函數上了,它的作用是羅列出當前對象的所有屬性,包括父類的。其實,前面提到的命名空間是的__dict__成員,所有與該對象對應的屬性全部放在這個字典裡。

我們列印出來看看

view plaincopy to clipboardprint?
  1. T.__dict__:  {'__dict__': , '__module__': '__main__', '__weakref__': , 'age': 21, '__doc__': None}  
  2.   
  3. t.__dict__:  {'name': 'ilovebaiyang'}  

這一下才會和我們想象的一樣,name屬性只存在執行個體中。
接下來是屬性的尋找:
如果我們要列印t.age,怎麼搜尋

  • 1.先尋找該執行個體的__dict__,如果有,返回,否則進行第二步
  • 2.尋找類的__dict__,如果有返回,沒有的話,繼續尋找該類的父類,直到基類,如果還沒有,拋出異常。

當然,其實python中的尋找還做了很多其他事,特別是一些隱含的調用,如果我們重寫這些隱含的調用,就可以寫出符合我們的資料。
看下面的例子:

view plaincopy to clipboardprint?
  1. class T(object):  
  2.     def __setattr__(self, name, value):  
  3.         print "__setattr__ called "  
  4.         object.__setattr__(self, name, value)  
  5.   
  6.     def __getattr__(self, name):  
  7.         print "__getattr__ called "   
  8.   
  9.     def __getattribute__(self, name):  
  10.         print "__getattribute__ called"  
  11.         return object.__getattribute__(self, name)  
  12.   
  13. t = T()  
  14. t.name = "baiyang"  
  15. print "t", t.name  
  16. t.baiyang  

結果:

  1. __setattr__ called  
  2. t __getattribute__ called  
  3. baiyang  
  4. __getattribute__ called  
  5. __getattr__ called  

分析以上的結果,當t.name被執行時,先調用了__setattr__函數;當print “t”, t.name時,調用了__getattribute__函數;當t.baiyang時,調用了__getattr__函數,因為t沒有baiyang這個屬性,故調用這個函數。

其實簡單的想一下,會明白,我們在操作namespace這個字典時,我們都會隱式的調用相應的函數,這些函數可以用來進行資料的驗證。
總結一下,在操作類的執行個體的屬性時,我們需要關注一下函數:
object.__setattr__(self, name, value)
object.__getattr__(self, name)
object.__delattr__(self, name)
object.__getattribute__(self, name)

其中你對任何對象的屬性訪問時,都會隱式的調用__getattribute__方法,比如你調用t.__dict__,其實你執行了t.__getattribute__(“__dict__”)函數。

神奇的python,把字典用的如此靈活,由此可以看出字典在python的地位是何其的重要。

在這裡,我們或許想到了怎麼不去隱式的調用這些函數,對,我們可以直接去操作類或者類執行個體的__dict__。看看下面的例子:

view plaincopy to clipboardprint?
  1. class T(object):  
  2.     age = 21  
  3.     def __setattr__(self, name, value):  
  4.         print "__setattr__ called "  
  5.         object.__setattr__(self, name, value)  
  6.   
  7.     def __getattr__(self, name):  
  8.         print "__getattr__ called "   
  9.   
  10.     def __getattribute__(self, name):  
  11.         print "__getattribute__ called"  
  12.         return object.__getattribute__(self, name)  
  13.   
  14. t = T()  
  15. t.__dict__["name"] = "baiyang"  
  16. print "t.__dict__: ", t.__dict__["name"]  
  17. print "t.age: ", t.age  
  18. print "t.__dict__['age']: ", t.__dict__["age"]  

結果

view plaincopy to clipboardprint?
  1. __getattribute__ called  
  2. t.__dict__:  __getattribute__ called  
  3. baiyang  
  4. t.age:  __getattribute__ called  
  5. 21  
  6. t.__dict__['age']:  __getattribute__ called  
  7.   
  8. Traceback (most recent call last):  
  9.   File "C:\Users\Administrator\Desktop\lab\SogouW\Freq\test.py", line 18, in  
  10.     print "t.__dict__['age']: ", t.__dict__["age"]  
  11. KeyError: 'age'  

我們來分析一下:
1.t__dict__["name"] = “baiyang”其中調用了__getattribute__函數,因為__dict__本身也是一個屬性的,所以它必須會執行的;但是你會發現此時__setattr__並沒有執行,達到了我們想要的效果;
2.print “t.age: “, t.age
print “t.__dict__['age']: “, t.__dict__["age"]這才是重點,第二條語句拋出了KeyError的異常,再一次證明了age只是存在於類的namespace中。

最後,我們與python中的descriptor進行比較:
可以看這篇文章,我就不細講了。
主要一點就是descriptor對應的函數是
object.__get__(self, instance, owner)
object.__set__(self, instance, value)
object.__delete__(self, instance)
可以看出少了attr這個詞,也以為著我們必須將他們區分看。descriptor是對類的執行個體進行的操作,內建函數property()就是通過這個方式實現的。看了此文,是不是對python的工作機制更加瞭解了呢?
好了,在這裡提幾個問吧,你可以去網上搜到答案

  • 如何建立immutable的資料,我之前的一篇文章已經給出了答案。
  • 如何建立singleton模式的資料

如果你明白了上面的文章,你就會明白,不論你想寫出什麼樣的資料,只要去重寫python中一些內在的函數即可。

 

原文:http://www.ibaiyang.org/2012/05/10/data-model-in-python/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.