1. 程式人生 > >Python的__getattribute__ vs __getattr__的妙用

Python的__getattribute__ vs __getattr__的妙用

  這裡的屬性即包括屬性變數,也包括屬性方法。即類的變數和方法。    當訪問某個例項屬性時, getattribute會被無條件呼叫,如未實現自己的getattr方法,會丟擲 AttributeError提示找不到這個屬性,如果自定義了自己getattr方法的話,方法會在這種找不到屬性的情況下被呼叫,比如上面的例子中的情況。所以在找不到屬性的情況下通過實現自定義的getattr方法來實現一些功能是一個不錯的方式,因為它不會像getattribute方法每次都會呼叫可能會影響一些正常情況下的屬性訪問     使用這幾個方法可以實現攔截器啥、動態代理、統一log等功能。     舉例:   1、使用__getattribute__實現統一的列印日誌功能。使用__getattribute__方法攔截了屬性和方法的訪問。__getattribute__只有在新式類中才能使用。   
# -*- coding: utf-8
-*- class Fjs(object): def __init__(self, name): self.name = name def hello(self): print "said by : ", self.name def __getattribute__(self, item): print "訪問了特性:" + item return object.__getattribute__(self, item) fjs = Fjs("fjs") print fjs.name fjs.hello()

輸出:

訪問了特性:name
fjs
訪問了特性:hello
said by :  訪問了特性:name
fjs

  2、這裡通過__getattr__方法,將所有的特性的訪問都路由給了內部的fjs物件

# -*- coding: utf-8 -*-
class Fjs(object):
    def __init__(self, name):
        self.name = name
 
    def hello(self):
        print "said by : ", self.name
 
    def fjs(self, name):
        
if name == self.name: print "yes" else: print "no" class Wrap_Fjs(object): def __init__(self, fjs): self._fjs = fjs def __getattr__(self, item): if item == "hello": print "呼叫hello方法了" elif item == "fjs": print "呼叫fjs方法了" return getattr(self._fjs, item) fjs = Wrap_Fjs(Fjs("fjs")) fjs.hello() fjs.fjs("fjs")

輸出:

呼叫hello方法了
said by :  fjs
呼叫fjs方法了
yes

  3、使用類的繼承實現。則不會路由,子類直接繼承了父類的屬性和方法

# -*- coding: utf-8 -*-
class Fjs(object):
    def __init__(self, name):
        self.name = name
 
    def hello(self):
        print "said by : ", self.name
 
    def fjs(self, name):
        if name == self.name:
            print "yes"
        else:
            print "no"
 
class Wrap_Fjs(Fjs):
    def __init__(self, fjs):
        self._fjs = fjs
 
    def __getattr__(self, item):
        if item == "hello":
            print "呼叫hello方法了"
        elif item == "fjs":
            print "呼叫fjs方法了"
        return getattr(self._fjs, item)
 
fjs = Wrap_Fjs(Fjs("fjs"))
fjs.hello()
fjs.fjs("fjs")

輸出:

said by :  fjs
yes

  4、猜一下結果,理解其妙用

# 例子在原來的基礎上簡化了一下,排除依賴和干擾,詳細參見原專案
class UrlGenerator(object):
    def __init__(self, root_url):
        self.url = root_url

    def __getattr__(self, item):
        if item == 'get' or item == 'post':
            print self.url
        return UrlGenerator('{}/{}'.format(self.url, item))


url_gen = UrlGenerator('http://xxxx')
url_gen.users.show.get

  5、通過轉換,可以像訪問屬性一樣訪問dict中的鍵值對

class ObjectDict(dict):
    def __init__(self, *args, **kwargs):
        super(ObjectDict, self).__init__(*args, **kwargs)

    def __getattr__(self, name):
        value =  self[name]
        if isinstance(value, dict):
            value = ObjectDict(value)
        return value

if __name__ == '__main__':
    od = ObjectDict(asf={'a': 1}, d=True)
    print od.asf, od.asf.a     # {'a': 1} 1
    print od.d                 # True

 

  參考: 1、https://www.jianshu.com/p/885d59db57fc 2、https://www.cnblogs.com/xybaby/p/6280313.html