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

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

特殊方法 (2)

書接上回,不管是實例還是類,都用__dict__來存儲屬性和方法,可以籠統(tǒng)地把屬性和方法稱為成員或者特性,用一句籠統(tǒng)的話說,就是__dict__存儲對象成員。但,有時候訪問的對象成員沒有存在其中,就是這樣:

>>> class A(object):
...     pass
... 
>>> a = A()
>>> a.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'x'

x 不是實例的成員,用 a.x 訪問,就出錯了,并且錯誤提示中報告了原因:“'A' object has no attribute 'x'”

在很多情況下,這種報錯是足夠的了。但是,在某種我現(xiàn)在還說不出的情況下,你或許不希望這樣報錯,或許希望能夠有某種別的提示、操作等。也就是我們更希望能在成員不存在的時候有所作為,不是等著報錯。

要處理類似的問題,就要用到本節(jié)中的知識了。

__getattr__、__setattr__和其它類似方法

還是用上面的例子,如果訪問 a.x,它不存在,那么就要轉(zhuǎn)向到某個操作。我們把這種情況稱之為“攔截”。就好像“尋隱者不遇”,卻被童子“遙指杏花村”,將你“攔截”了。在 Python 中,有一些方法就具有這種“攔截”能力。

  • __setattr__(self,name,value):如果要給 name 賦值,就調(diào)用這個方法。
  • __getattr__(self,name):如果 name 被訪問,同時它不存在的時候,此方法被調(diào)用。
  • __getattribute__(self,name):當(dāng) name 被訪問時自動被調(diào)用(注意:這個僅能用于新式類),無論 name 是否存在,都要被調(diào)用。
  • __delattr__(self,name):如果要刪除 name,這個方法就被調(diào)用。

如果一時沒有理解,不要緊,是正常的。需要用例子說明。

>>> class A(object):
...     def __getattr__(self, name):
...         print "You use getattr"
...     def __setattr__(self, name, value):
...         print "You use setattr"
...         self.__dict__[name] = value
... 

類 A 是新式類,除了兩個方法,沒有別的屬性。

>>> a = A()
>>> a.x
You use getattr

a.x,按照本節(jié)開頭的例子,是要報錯的。但是,由于在這里使用了__getattr__(self, name) 方法,當(dāng)發(fā)現(xiàn) x 不存在于對象的__dict__中的時候,就調(diào)用了__getattr__,即所謂“攔截成員”。

>>> a.x = 7
You use setattr

給對象的屬性賦值時候,調(diào)用了__setattr__(self, name, value)方法,這個方法中有一句 self.__dict__[name] = value,通過這個語句,就將屬性和數(shù)據(jù)保存到了對象的__dict__中,如果在調(diào)用這個屬性:

>>> a.x
7

它已經(jīng)存在于對象的__dict__之中。

在上面的類中,當(dāng)然可以使用__getattribute__(self, name),因為它是新式類。并且,只要訪問屬性就會調(diào)用它。例如:

>>> class B(object):
...     def __getattribute__(self, name):
...         print "you are useing getattribute"
...         return object.__getattribute__(self, name)
...

為了與前面的類區(qū)分,新命名一個類名字。需要提醒注意,在這里返回的內(nèi)容用的是 return object.__getattribute__(self, name),而沒有使用 return self.__dict__[name]像是。因為如果用這樣的方式,就是訪問 self.__dict__,只要訪問這個屬性,就要調(diào)用`getattribute``,這樣就導(dǎo)致了無線遞歸下去(死循環(huán))。要避免之。

>>> b = B()
>>> b.y
you are useing getattribute
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __getattribute__
AttributeError: 'B' object has no attribute 'y'
>>> b.two
you are useing getattribute
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __getattribute__
AttributeError: 'B' object has no attribute 'two'

訪問不存在的成員,可以看到,已經(jīng)被__getattribute__攔截了,雖然最后還是要報錯的。

>>> b.y = 8
>>> b.y
you are useing getattribute
8

當(dāng)給其賦值后,意味著已經(jīng)在__dict__里面了,再調(diào)用,依然被攔截,但是由于已經(jīng)在__dict__內(nèi),會把結(jié)果返回。

當(dāng)你看到這里,是不是覺得上面的方法有點魔力呢?不錯。但是,它有什么具體應(yīng)用呢?看下面的例子,能給你帶來啟發(fā)。

#!/usr/bin/env Python
# coding=utf-8

"""
study __getattr__ and __setattr__
"""

class Rectangle(object):
    """
    the width and length of Rectangle
    """
    def __init__(self):
        self.width = 0
        self.length = 0

    def setSize(self, size):
        self.width, self.length = size
    def getSize(self):
        return self.width, self.length

if __name__ == "__main__":
    r = Rectangle()
    r.width = 3
    r.length = 4
    print r.getSize()
    r.setSize( (30, 40) )
    print r.width
    print r.length

上面代碼來自《Beginning Python:From Novice to Professional,Second Edittion》(by Magnus Lie Hetland),根據(jù)本教程的需要,稍作修改。

$ python 21301.py 
(3, 4)
30
40

這段代碼已經(jīng)可以正確運行了。但是,作為一個精益求精的程序員??傆X得那種調(diào)用方式還有可以改進的空間。比如,要給長寬賦值的時候,必須賦予一個元組,里面包含長和寬。這個能不能改進一下呢?

#!/usr/bin/env Python
# coding=utf-8

"""
study __getattr__ and __setattr__
"""

class Rectangle(object):
    """
    the width and length of Rectangle
    """
    def __init__(self):
        self.width = 0
        self.length = 0

    def setSize(self, size):
        self.width, self.length = size
    def getSize(self):
        return self.width, self.length

    size = property(getSize, setSize)

if __name__ == "__main__":
    r = Rectangle()
    r.width = 3
    r.length = 4
    print r.size
    r.size = 30, 40
    print r.width
    print r.length

以上代碼的運行結(jié)果同上。但是,因為加了一句 size = property(getSize, setSize),使得調(diào)用方法是不是更優(yōu)雅了呢?原來用 r.getSize(),現(xiàn)在使用 r.size,就好像調(diào)用一個屬性一樣。難道你不覺得眼熟嗎?在《多態(tài)和封裝》中已經(jīng)用到過 property 函數(shù)了,雖然寫法略有差別,但是作用一樣。

本來,這樣就已經(jīng)足夠了。但是,因為本節(jié)中出來了特殊方法,所以,一定要用這些特殊方法從新演繹一下這段程序。雖然重新演繹的不一定比原來的好,主要目的是演示本節(jié)的特殊方法應(yīng)用。

#!/usr/bin/env Python
# coding=utf-8

class NewRectangle(object):
    def __init__(self):
        self.width = 0
        self.length = 0

    def __setattr__(self, name, value):
        if name == "size":
            self.width, self.length = value
        else:
            self.__dict__[name] = value

    def __getattr__(self, name):
        if name == "size":
            return self.width, self.length
        else:
            raise AttributeError

if __name__ == "__main__":
    r = NewRectangle()
    r.width = 3
    r.length = 4
    print r.size
    r.size = 30, 40
    print r.width
    print r.length

除了類的樣式變化之外,調(diào)用樣式?jīng)]有變。結(jié)果是一樣的。

這就算了解了一些這些屬性了吧。但是,有一篇文章是要必須推薦給讀者閱讀的:Python Attributes and Methods,讀了這篇文章,對 Python 的對象屬性和方法會有更深入的理解。

獲得屬性順序

通過實例獲取其屬性(也有說特性的,名詞變化了,但是本質(zhì)都是屬性和方法),如果在__dict__中有相應(yīng)的屬性,就直接返回其結(jié)果;如果沒有,會到類屬性中找。比如:

#!/usr/bin/env Python
# coding=utf-8

class A(object):
    author = "qiwsir"
    def __getattr__(self, name):
        if name != "author":
            return "from starter to master."

if __name__ == "__main__":
    a = A()
    print a.author
    print a.lang

運行程序:

$ python 21302.py 
qiwsir
from starter to master.

當(dāng) a = A() 后,并沒有為實例建立任何屬性,或者說實例的__dict__是空的,這在上節(jié)中已經(jīng)探討過了。但是如果要查看 a.author,因為實例的屬性中沒有,所以就去類屬性中找,發(fā)現(xiàn)果然有,于是返回其值 "qiwsir"。但是,在找 a.lang 的時候,不僅實例屬性中沒有,類屬性中也沒有,于是就調(diào)用了__getattr__()方法。在上面的類中,有這個方法,如果沒有__getattr__()方法呢?如果沒有定義這個方法,就會引發(fā) AttributeError,這在前面已經(jīng)看到了。

這就是通過實例查找特性的順序。


總目錄   |   上節(jié):特殊方法(1)   |   下節(jié):迭代器

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