Python中的getattr()和__getattr__方法

在看python核心編程時,看到了getattr()內建函數和__getattr__,但不太理解,就仔細的看了下並查閱了一些資料,大致瞭解了它們是做什麼的。

getattr()
先在python解釋器看下getattr()的幫助
Help on built-in function getattr in module __builtin__:

getattr(...)
    getattr(object, name[, default]) -> value
    
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
(END)

getattr(),顧名思義就是獲取對象的屬性,getattr(x, 'y')等價於 x.y。 第三個參數可有可無,當給getattr()第三個參數時,如果對應的屬性不存在,它會作爲返回值返回。
看下面代碼:

class Test(object):
     val = 1
 
>>> Test.val
1
>>> getattr(Test, 'val')
1
>>> getattr(Test, 'va', 5)
5


因爲val是Test的屬性,所以通過getattr可以獲取到val的值,而va則不是Test的屬性,但我們傳進了第三個參數5,所以返回5。


使用 內建函數dir()可以查看一個對象的屬性,如下
>>> dir(Test)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'val']

再看看下面的例子:
dir1 = {}
dir1['a'] = 1
dir2['b'] = 2
>>> getattr(dir1, 'a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>

AttributeError: 'dict' object has no attribute 'a'


但爲什麼通過getattr獲取不了dir1['a']的值呢?根據解釋器的錯誤信息就可以看出dir1沒有名爲‘a'的屬性。

再使用dir(dir1)來看下

>>> dir(dir1)

['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']


dir1的確沒有'a'這個屬性,但是有__str__這個屬性

>>> getattr(dir1, '__str__')()
"{'a': 1, 'b': 2}"
>>> dir1.__str__()
"{'a': 1, 'b': 2}"


在調用getattr(obj,name)時,如果實例obj沒有name屬性,則會去調用類中的__getattr__

__getattr__
__getattr__()是僅當屬性不能在實例的__dict__或它的類(類的__dict__),或父類的__dict__中找到時,才被調用。一般在代碼中包含一個對getattr()內建函數的調用

每一個類都會用一個字典,把它包含的屬性放到自己的字典裏。


>>> Test.__dict__

dict_proxy({'__dict__': <attribute '__dict__' of 'Test' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None, 'val': 1})


看下面的示例代碼
#!/usr/bin/env python


class Test1(object):


    def __init__(self, obj):
        print "In __init__"
        self.data = obj


    def __str__(self):
        print "In __str__"
        return str(self.data)


    __repr__ = __str__


    def get_attr(self):
        print "In getattr"
        return self.data


    def __getattr__(self, attr):
        print "In __getattr__"
        return getattr(self.data, attr)


if __name__ == '__main__':
    myString = Test1('hello')
    print myString
    print myString.upper()
    print myString.get_attr()


看下輸出結果
cullen@cullen--machine:~/python$ ./getattr.py 
In __init__
In __str__
hello
In __getattr__
HELLO
In getattr
hello


下面對結果進行簡要的分析
myString = Test1('hello')
//輸出結果In __init__, 不用解釋了吧
print myString
//輸出結果
//In __str__
//hello

print myString.upper()
//輸出結果
//In __getattr__
//HELLO

重點就在這裏,我們的實例myString並沒有upper()這個屬性,所以myString.upper()等價於getattr(myString.data, upper)()
print myString.get_attr()
//輸出結果,因爲gets_attr()是myString的屬性,所以沒有調用__getattr__。
//In getattr
//hello



                                       







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章