python對象的創建和銷毀


對象的創建

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM