<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                書接上回,不管是實例還是類,都用`__dict__`來存儲屬性和方法,可以籠統地把屬性和方法稱為成員或者特性,用一句籠統的話說,就是`__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'” 在很多情況下,這種報錯是足夠的了。但是,在某種我現在還說不出的情況下,你或許不希望這樣報錯,或許希望能夠有某種別的提示、操作等。也就是我們更希望能在成員不存在的時候有所作為,不是等著報錯。 要處理類似的問題,就要用到本節中的知識了。 ## [](https://github.com/qiwsir/StarterLearningPython/blob/master/213.md#__getattr____setattr__和其它類似方法)`__getattr__`、`__setattr__`和其它類似方法 還是用上面的例子,如果訪問`a.x`,它不存在,那么就要轉向到某個操作。我們把這種情況稱之為“攔截”。就好像“尋隱者不遇”,卻被童子“遙指杏花村”,將你“攔截”了。在python中,有一些方法就具有這種“攔截”能力。 * `__setattr__(self,name,value)`:如果要給name賦值,就調用這個方法。 * `__getattr__(self,name)`:如果name被訪問,同時它不存在的時候,此方法被調用。 * `__getattribute__(self,name)`:當name被訪問時自動被調用(注意:這個僅能用于新式類),無論name是否存在,都要被調用。 * `__delattr__(self,name)`:如果要刪除name,這個方法就被調用。 如果一時沒有理解,不要緊,是正常的。需要用例子說明。 ~~~ >>> 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`,按照本節開頭的例子,是要報錯的。但是,由于在這里使用了`__getattr__(self, name)`方法,當發現`x`不存在于對象的`__dict__`中的時候,就調用了`__getattr__`,即所謂“攔截成員”。 ~~~ >>> a.x = 7 You use setattr ~~~ 給對象的屬性賦值時候,調用了`__setattr__(self, name, value)`方法,這個方法中有一句`self.__dict__[name] = value`,通過這個語句,就將屬性和數據保存到了對象的`__dict__`中,如果在調用這個屬性: ~~~ >>> a.x 7 ~~~ 它已經存在于對象的`__dict__`之中。 在上面的類中,當然可以使用`__getattribute__(self, name)`,因為它是新式類。并且,只要訪問屬性就會調用它。例如: ~~~ >>> class B(object): ... def __getattribute__(self, name): ... print "you are useing getattribute" ... return object.__getattribute__(self, name) ... ~~~ 為了與前面的類區分,新命名一個類名字。需要提醒注意,在這里返回的內容用的是`return object.__getattribute__(self, name)`,而沒有使用`return self.__dict__[name]`像是。因為如果用這樣的方式,就是訪問`self.__dict__`,只要訪問這個屬性,就要調用`__getattribute__``,這樣就導致了無線遞歸下去(死循環)。要避免之。 ~~~ >>> 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' ~~~ 訪問不存在的成員,可以看到,已經被`__getattribute__`攔截了,雖然最后還是要報錯的。 ~~~ >>> b.y = 8 >>> b.y you are useing getattribute 8 ~~~ 當給其賦值后,意味著已經在`__dict__`里面了,再調用,依然被攔截,但是由于已經在`__dict__`內,會把結果返回。 當你看到這里,是不是覺得上面的方法有點魔力呢?不錯。但是,它有什么具體應用呢?看下面的例子,能給你帶來啟發。 ~~~ #!/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),根據本教程的需要,稍作修改。 ~~~ $ python 21301.py (3, 4) 30 40 ~~~ 這段代碼已經可以正確運行了。但是,作為一個精益求精的程序員。總覺得那種調用方式還有可以改進的空間。比如,要給長寬賦值的時候,必須賦予一個元組,里面包含長和寬。這個能不能改進一下呢? ~~~ #!/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 ~~~ 以上代碼的運行結果同上。但是,因為加了一句`size = property(getSize, setSize)`,使得調用方法是不是更優雅了呢?原來用`r.getSize()`,現在使用`r.size`,就好像調用一個屬性一樣。難道你不覺得眼熟嗎?在[《多態和封裝》](https://github.com/qiwsir/StarterLearningPython/blob/master/211.md)中已經用到過property函數了,雖然寫法略有差別,但是作用一樣。 本來,這樣就已經足夠了。但是,因為本節中出來了特殊方法,所以,一定要用這些特殊方法從新演繹一下這段程序。雖然重新演繹的不一定比原來的好,主要目的是演示本節的特殊方法應用。 ~~~ #!/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 ~~~ 除了類的樣式變化之外,調用樣式沒有變。結果是一樣的。 這就算了解了一些這些屬性了吧。但是,有一篇文章是要必須推薦給讀者閱讀的:[Python Attributes and Methods](http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html),讀了這篇文章,對python的對象屬性和方法會有更深入的理解。 ## [](https://github.com/qiwsir/StarterLearningPython/blob/master/213.md#獲得屬性順序)獲得屬性順序 通過實例獲取其屬性(也有說特性的,名詞變化了,但是本質都是屬性和方法),如果在`__dict__`中有相應的屬性,就直接返回其結果;如果沒有,會到類屬性中找。比如: ~~~ #!/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. ~~~ 當`a = A()`后,并沒有為實例建立任何屬性,或者說實例的`__dict__`是空的,這在上節中已經探討過了。但是如果要查看`a.author`,因為實例的屬性中沒有,所以就去類屬性中找,發現果然有,于是返回其值`"qiwsir"`。但是,在找`a.lang`的時候,不僅實例屬性中沒有,類屬性中也沒有,于是就調用了`__getattr__()`方法。在上面的類中,有這個方法,如果沒有`__getattr__()`方法呢?如果沒有定義這個方法,就會引發AttributeError,這在前面已經看到了。 這就是通過實例查找特性的順序。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看