不少pythonic的代碼都會用到內置方法,根據本身的經驗,羅列一下本身知道的內置方法。python
這三個方法是字典類的內置方法,分別對應於查找、設置、刪除操做,以一個簡單的例子說明:閉包
class A(dict): def __getitem__(self, key): print '__getitem__' return super(A, self).__getitem__(key) def __setitem__(self, key, value): print '__setitem__' return super(A, self).__setitem__(key, value) def __delitem__(self, key): print '__delitem__' return super(A, self).__delitem__(key) a = A() a[1] = 1 b = a[1] del a[1] a.get(1)
上面的代碼中a[1] = 1
實際上調用的就是a.__setitem__(1, 1)
, a[1]
調用的是a.__get__item__(1)
, del a[1]
調用的是a.__setitem__(1)
。須要注意的是,字典示例的get方法和__getitem__方法不存在調用關係,二者互不影響。函數
__getattribute__和__getattr__都是從python對象示例中獲取成員變量的方法,差異在於__getattribute__在任什麼時候候都會調用,而__getattr__只有在__getattribute__執行完成以後而且沒有找到成員變量的時候纔會執行。__setattr__在給成員變量賦值的時候調用,__delattr__在回收成員變量的時候調用,一下面的例子說明:code
class A(object): x = [] def __getattribute__(self, name): print '__getattribute__' return super(A, self).__getattribute__(name) def __setattr__(self, key, value): print '__setattr__' return super(A, self).__setattr__(key, value) def __getattr__(self, item): print '__getattr__' def __delattr__(self, item): print '__delattr__' return super(A, self).__delattr__(item) a = A() a.x a.y b = getattr(a, 'x') b = getattr(a, 'y') a.x = 1 a.y = 1 setattr(a, 'x', 1) setattr(a, 'y', 1) del a.x del a.y
由於x是a的成員變量,a.x會調用a.__getattribue__('x')
,而y不是a的成員變量,在調用a.__getattribue__('y')
以後還會調用a.__getattr__('y')
,內置方法getattr也是按照此順序調用,惟一的區別在於getattr在成員變量不存在的時候不會拋出異常,而是給一個默認值。a.x = 1
和setattr(a, 'x', 1)
都會調用a.__setattr__('x', 1)
,若是原來的成員變量不存在,__setattr__會給實例增長一個成員變量,而不是拋出異常。對象
若是重載了__call__方法,則實例對象就能夠像方法同樣調用了。若是實例a的類實現了這個方法,那麼a(*args, **kwargs)
就會調用a.__call__(*args, **kwargs)
。用這種方法能夠簡單方便的實現裝飾器,以下所示:get
class A(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print '__call__' return self.func(*args, **kwargs) @A def foo(x): return x foo(1)
裝飾器語法糖至關於foo = A(foo)
, 和閉包不一樣,foo已經不是一個函數而是類A的實例。foo(1)
會執行foo.__call__(1)
。固然這個例子實現的裝飾器並很差,會改變foo的函數簽名,並且也不能裝飾類方法。it
此外元類的__call__也能夠控制實例的建立過程,由於當類建立對象時,元類的__call__函數就被調用,進而調用type.__call__建立對象,type.__call__回依次調用類的__new__和__init__生成實例。以單例模式爲例:class
class Singleton(type): def __call__(cls, *args): print "Singleton call" if not hasattr(cls, 'instance'): cls.instance = super(Singleton, cls).__call__(*args) return cls.instance class Cache(object): __metaclass__ = Singleton def __new__(cls, *args): print "Cache new" return object.__new__(cls, *args) def __init__(cls, *args, **kwargs): print "Cache init" a = Cache() b = Cache() print a is b
這三個方法分別對應於描述器的查詢、設置、刪除函數,仍是以一個簡單的例子來講明:import
class A(object): def __get__(self, instance, owner): print '__get__' def __set__(self, instance, value): print '__set__' class B(object): a = A() b = B() c = b.a b.a = 1
類A的示例a做爲b的成員變量時候,訪問示例b中成員變量a的時候會調用a.__get__(b, B)
,修改b中成員變量a的時候會調用a.__set__(b, 1)
。須要注意的是,當用B.a訪問的時候參數instance爲None。實際上像classmethod,staticmethod這樣的裝飾器都是經過裝飾器來實現的,經過裝飾器就能夠解決上面不能做爲類方法裝飾器的問題。變量
import types class Profiled(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): return self.func(*args, **kwargs) def __get__(self, instance, owner): if instance is None: return self else: return types.MethodType(self, instance) class Spam(object): @Profiled def bar(self, x): return x + 1 s = Spam() print s.bar(5)
在__get__方法中,不是Spam.bar調用,則instance不爲None的狀況下,會用types.MethodType把bar和s作一個綁定,s.bar(5)等價於執行了bar.__get__(s, Spam).__call__(5)
,看起來很繞,但實際上用起來很方便。