對象的創建
pyhton用__new__來創建對象(__new__相當於Java中的構建函數),對象創建好之后會立即調用__init__方法,__init__方法有個參數self就是剛才__new__創建好的那個對象。通過我們有__init__方法中給對象的屬性進行賦值,或者動態線對象添加屬性並賦值。
class Student(object): cnt = 0 # 用於記錄該類的實例創建了多少個 def __new__(cls, *args, **kwargs): print '__new__' cls.cnt += 1 return super(Student, cls).__new__(cls, *args, **kwargs) def __init__(self): print '__init__' self.name = 'ELE' + str(self.cnt) if __name__ == '__main__': inst1 = Student() print inst2 = Student() print inst2.name print Student.cnt
輸出
__new__ __init__ __new__ __init__ ELE2 2
對象被當作函數來使用時,會調用對象的__call__方法,相當於是__call__重載了小括號運算符。
class Student(object): def __init__(self): self.name='orisun' def __call__(self): print '__call__' self.name = 'SOS' if __name__ == '__main__': inst = Student() print inst.name print inst() print inst.name
輸出
orisun __call__ SOS
用__new__實現單例模式
# coding:utf-8 class Singleton1(object): name = '' def __new__(cls, *args, **kwargs): if not '_instance' in vars(cls): print 'creating instance of Singleton1' cls._instance = super(Singleton1, cls).__new__(cls) if len(args) > 0: cls.name = args[0] elif 'name' in kwargs: cls.name = kwargs[name] return cls._instance class Singleton2(object): name = '' def __new__(cls, *args, **kwargs): if not '_instance' in vars(cls): print 'creating instance of Singleton2' cls._instance = super(Singleton2, cls).__new__(cls) if len(args) > 0: cls.name = args[0] elif 'name' in kwargs: cls.name = kwargs['name'] return cls._instance if __name__ == '__main__': inst1 = Singleton1('a') inst2 = Singleton1(name='b') print inst1 is inst2 print inst1.name print inst2.name print '*' * 10 inst3 = Singleton2(name='b') inst4 = Singleton2('a') print inst3 is inst4 print inst3.name print inst4.name
輸出:
creating instance of Singleton1 True a a ********** creating instance of Singleton2 True b b
判斷2個對象是否為同一個對象我們用了關鍵字is。
上例中我們充分利用了__new__()函數的兩個參數:*args和**kwargs。
用__new__實現對實例的緩存
# coding:utf-8 import weakref class Cached(object): _cache = weakref.WeakValueDictionary() def __new__(cls, *args, **kwargs): name = None if len(args) > 0: name = args[0] elif 'name' in kwargs: name = kwargs['name'] else: name = '' if not name in cls._cache: _instance = super(Cached, cls).__new__(cls) cls._cache[name] = _instance return cls._cache[name] def __init__(self, *args, **kwargs): if len(args) > 0: self.name = args[0] elif 'name' in kwargs: self.name = kwargs['name'] if __name__ == '__main__': inst1 = Cached('a') inst2 = Cached(name='b') inst3 = Cached(name='a') print 'inst1 is inst2' if (inst1 is inst2) else 'inst1 is not inst2' print 'inst1 is inst3' if (inst1 is inst3) else 'inst1 is not inst3' print 'inst1.name =', inst1.name print 'inst2.name =', inst2.name print 'inst3.name =', inst3.name
輸出:
inst1 is not inst2 inst1 is inst3 inst1.name = a inst2.name = b inst3.name = a
對象的銷毀
python和Java一樣都是垃圾自動回收,不需要我們顯示地銷毀對象。執行del obj時會調用對象的__del__方法,這樣對象的引用計數會減1,當對象的引用計數為0時,對象就會被銷毀,內存就會被回收。
import gc class A(object): def __init__(self): self.large_list=[i for i in xrange(10000000)] def __del__(self): print "__del__" @profile def foo(): a=A() b=a del b del a gc.collect() print if __name__ == '__main__': foo()
我們使用memory_profiler模塊監控每行代碼內存的變化。
$ python -m memory_profiler a.py __del__ Filename: a.py Line # Mem usage Increment Line Contents ================================================ 13 9.066 MiB 0.000 MiB @profile 14 def foo(): 15 251.051 MiB 241.984 MiB a=A() 16 251.051 MiB 0.000 MiB b=a 17 251.051 MiB 0.000 MiB del b 18 243.863 MiB -7.188 MiB del a 19 20.863 MiB -223.000 MiB gc.collect() 20 20.863 MiB 0.000 MiB print
可見del b時,對象的引用計數還沒有變為0,故內存占用沒有絲毫減少。當del a時,對象的引用計數變為0,內存有所減少,但是對象占用的內存並沒有立即完全回收,直到顯式調用gc.collect()。
通過MetaClass創建類
class MetaClass(type): def __new__(cls,class_name,base_classes,attr_dict): print '__new__ in MetaClass' return super(MetaClass,cls).__new__(cls,class_name,base_classes,attr_dict) def __init__(cls,class_name,base_classes,attr_dict): print '__init__ in MetaClass' super(MetaClass, cls).__init__(class_name,base_classes,attr_dict) def __call__(cls,*args): print '__call__ in MetaClass' print 'AAAAAAAAAAAAAAA' super(MetaClass, cls).__call__(*args) print 'BBBBBBBBBBBBBBB' class A(object): __metaclass__=MetaClass name='orisun' def __new__(cls, *args, **kwargs): print '__new__ in A' return super(A, cls).__new__(cls, *args, **kwargs) def __init__(self): print '__init__ in A' if __name__ == '__main__': print '='*40 a=A() print '='*40
輸出
__new__ in MetaClass __init__ in MetaClass ======================================== __call__ in MetaClass AAAAAAAAAAAAAAA __new__ in A __init__ in A BBBBBBBBBBBBBBB ========================================
我們看到,不需要執行類A之外的任何代碼,單純是在定義完類A之后,MetaClass中的__new__和__init__就被執行了。
當創建類實例時,MetaClass中的__call__會被執行,__call__中調用super.__call__時,類A的__new__和__init__才被調到。
用MetaClass實現單例模式
# coding:utf-8 class Singleton(type): def __init__(cls, class_name, base_classes, attr_dict): cls.__instance = None super(Singleton, cls).__init__(class_name, base_classes, attr_dict) def __call__(cls, *args, **kwargs): if cls.__instance is None: cls.__instance = super(Singleton, cls).__call__(*args, **kwargs) return cls.__instance else: return cls.__instance class Segger(object): __metaclass__ = Singleton def __init__(self, name): self.name = name if __name__ == '__main__': inst1 = Segger('a') inst2 = Segger('b') print inst1 is inst2 print inst1.name print inst2.name
輸出:
True
a
a