代理类:
代理类的作用其实有继承有些类似,如果你想将某个实例的属性访问代理到内部另外一个实例中去,可以用继承也可以用代理。来看下代理的应用:
class A: def spam(self,x): print ‘in Class A x=%d‘ % x def foo(self): print ‘in Class A:foo()‘
class B1: def __init__(self): self._a=A() ⑴ def spam(self,x): return self._a.spam(x) ⑵ def foo(self): return self._a.foo() ⑶ def bar(self): pass if __name__ == "__main__": b=B1() b.spam(42) b.foo()
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
in Class A x=42
in Class A:foo()
在(1)中,将self._a赋值为A的实例。在(2)中,self._a.spam(x),self._a.foo其实等于A().spam(x)和A().foo().通过这样的方式,在B1中能够访问到A中的实现。这也就实现了spam()和foo()的代理
如果仅仅是两个函数需要代理,那么代码量还不算很大,但是如果有很多函数需要代理,每个函数在B1中都需要写一个对应的代理函数就很麻烦了。这种情况下使用__getattr__就方便很多
class A: def spam(self,x): print ‘in Class A x=%d‘ % x def foo(self): print ‘in Class A:foo()‘ class B: def __init__(self): self._a=A() def bar(self): pass def __getattr__(self, item): return getattr(self._a,item)
if __name__ == "__main__": b=B() b.spam(42) b.foo()
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
{‘name‘: ‘x‘}
in Class A x=42
in Class A:foo()
在实例以及类中找不到对应的属性的时候会调用__getattr__。上面的实现在调用b.spam(42)以及b.foo()的时候将会调用__getattr__。getattr(self._a,item)等价于self._a.item
创建不调用init方法的实例。Python中的__init__方法其实是一个构造函数,在调用对应的类实例的时候,首先调用__init__方法。但是有没有方法可以绕开执行__init__呢? __new__就可以达到这个目的,来看下面的例子。
class Date(object): def __init__(self,year,month,day): self.year=year self.month=month self.day=day
if __name__ == "__main__": d=Date.__new__(Date) print d.year
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
Traceback (most recent call last):
File "E:/py_prj/python_cookbook/chapter8.py", line 236, in <module>
print d.year
AttributeError: ‘Date‘ object has no attribute ‘year‘
首先通过Date.__new__(Date)创建一个实例,当执行d.year的时候提示没有year这个属性,这是因为没有执行__init__.如果添加下面的代码则不会有问题
print d.__init__(1,2,3) print d.year
注意:
只有在新式类中才会有__new__的方法,经典类中是没有的,因此要在python2.7中使用__new__方法,必须要继承自object。而python3.0中都是新式类。可以直接使用__new__
我们还可以将这个__new__写到类中去:
class Date(object): def __init__(self,year,month,day): self.year=year self.month=month self.day=day def __new__(cls, *args, **kwargs): print ‘new‘ print object.__new__(cls,*args, **kwargs) return object.__new__(cls,*args, **kwargs) if __name__ == "__main__": d=Date(2017,7,16)
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
new
<__main__.Date object at 0x017DD3D0>
通过上面的实现可以看到__new__其实反馈的就是__init__中的self.在实例创建过程中__new__方法优于__init__方法。另外在__new__中必须要有返回值,这个返回值就是生成的实例。所以__new__和__init__就像这么一个关系,__init__提供生产的原料self(但并不保证这个原料来源正宗,像上面那样它用的是另一个不相关的类的__new__方法类得到这个实例),而__init__就用__new__给的原料来完善这个对象(尽管它不知道这些原料是不是正宗的)
如果我们完全不想用__init__来初始化实例,可以用下面的方法:
class Date(object): @classmethod def today(cls,year,month,day): d=cls.__new__(cls) d.year=2017 d.month=7 d.day=16 return d if __name__ == "__main__": d=Date.today(2017,7,16) print d.year
通过classmethod修饰today方法,通过调用today方法也可以实现__init__方法
垃圾内存回收
一:垃圾内存回收:
在内部,创建一个对象时,Python总是在对象的C结构体里保存一个整数,称为 引用数。期初,Python将这个值设置为1:当引用数为0 的时候,就会销毁这个对象,然后释放内存
导致引用计数+1的情况:
- 对象被创建,例如n=1
- 对象被引用,例如n1=n
- 对象被作为参数,传入到一个函数中,例如func(n)
- 对象作为一个元素,存储在容器中,例如list1=[n,n1]
导致引用计数-1的情况
- 对象的别名被显式销毁,例如del a
- 对象的别名被赋予新的对象,例如a=2
- 一个对象离开它的作用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会)
- 对象所在的容器被销毁,或从容器中删除对象
参考下面的代码:
class Node(object): def __init__(self,val): self.value=val if __name__ == "__main__": n1=Node(‘abc‘) n2=Node(‘def‘) n3=Node(‘ghi‘) print sys.getrefcount(n1) print sys.getrefcount(n2) print sys.getrefcount(n3)
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
2
2
2
由于n1,n2,n3都被传入了getrefcount,按照上面计数的规则,因此最终的引用计数为2. 对应的关系如下图。
如果改变下引用,让n2引用n1.n2=n1.”ghi”被n1和n2同时引用,因此引用数变成2.而abc由于没有任何引用,所以引用计数为0,内存被清空
时间: 2024-10-10 08:13:03