代理类:
代理类的作用其实有继承有些类似,如果你想将某个实例的属性访问代理到内部另外一个实例中去,可以用继承也可以用代理。来看下代理的应用:
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的情况:

  1. 对象被创建,例如n=1
  2. 对象被引用,例如n1=n
  3. 对象被作为参数,传入到一个函数中,例如func(n)
  4. 对象作为一个元素,存储在容器中,例如list1=[n,n1]

导致引用计数-1的情况

  1. 对象的别名被显式销毁,例如del a
  2. 对象的别名被赋予新的对象,例如a=2
  3. 一个对象离开它的作用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会)
  4. 对象所在的容器被销毁,或从容器中删除对象

参考下面的代码:

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,内存被清空

python cookbook第三版学习笔记十四:类和对象(五)代理类以及内存回收的更多相关文章

  1. python cookbook第三版学习笔记十:类和对象(一)

    类和对象: 我们经常会对打印一个对象来得到对象的某些信息. class pair:     def __init__(self,x,y):         self.x=x         self. ...

  2. python cookbook第三版学习笔记十六:抽象基类

    假设一个工程中有多个类,每个类都通过__init__来初始化参数.但是可能有很多高度重复且样式相同的__init__.为了减少代码.我们可以将初始化数据结构的步骤归纳到一个单独的__init__函数中 ...

  3. python cookbook第三版学习笔记十五:property和描述

    8.5 私有属性: 在python中,如果想将私有数据封装到类的实例上,有两种方法:1 单下划线.2 双下划线 1 单下划线一般认为是内部实现,但是如果想从外部访问的话也是可以的 2 双下划线是则无法 ...

  4. python cookbook第三版学习笔记十二:类和对象(三)创建新的类或实例属性

    先介绍几个类中的应用__getattr__,__setattr__,__get__,__set__,__getattribute__,. __getattr__:当在类中找不到attribute的时候 ...

  5. python cookbook第三版学习笔记十九:未包装的函数添加参数

    比如有下面如下的代码,每个函数都需要判断debug的是否为True,而默认的debug为False def a(x,debug=False): if debug: print('calling a') ...

  6. python cookbook第三版学习笔记十八:可由用户修改的装饰器

    定义一个属性可由用户修改的装饰器: 在前面的介绍中使用装饰器来包装函数,这一章来介绍下如何让用户调整装饰器的属性. 首先来看下代码: from functools import wraps,parti ...

  7. python cookbook第三版学习笔记二十:可自定义属性的装饰器

    在开始本节之前,首先介绍下偏函数partial.首先借助help来看下partial的定义 首先来说下第一行解释的意思: partial 一共有三个部分: (1)第一部分也就是第一个参数,是一个函数, ...

  8. python cookbook第三版学习笔记六:迭代器与生成器

    假如我们有一个列表 items=[1,2,3].我们要遍历这个列表我们会用下面的方式 For i in items:   Print i 首先介绍几个概念:容器,可迭代对象,迭代器 容器是一种存储数据 ...

  9. python cookbook第三版学习笔记 一

    数据结构 假设有M个元素的列表,需要从中分解出N个对象,N<M,这会导致分解的值过多的异常.如下: record=['zhf','zhf@163.com','775-555-1212','847 ...

随机推荐

  1. Maven 多模块父子工程 (含Spring Boot示例)

    一.为什么要用Maven多模块 假设有这样一个项目,很常见的Java Web应用.在这个应用中,我们分了几层: Dao Service Web 对应的,在一个项目中,我们会看到一些包名: org.xx ...

  2. Data structure basics - Java Implementation

    Stack & Queue Implementations FixedCapacityQueue package cn.edu.tsinghua.stat.mid_term; import j ...

  3. jeesite导入数据库错误:java.sql.SQLException: Incorrect string value: '\xE4\xB8\xAD\xE5\x9B\xBD' for column 'name' at row 1问题解决

    如果使用mvn antrun:run -Pinit-db进行数据库导入导致出现如下错误: 解决方法: 这个是由于新建数据库没有选择默认字符集导致的,只要选择utf-8即可.

  4. log4j 2使用properties文件进行配置

    网上不少文章给的都是用xml进行配置,也会提到无法使用properties文件对log4j进行配置,但那应该只是在他们写文章的时候才是如此,最新的2.8.2版本经过我试验后是可以做到的当然该文件最好放 ...

  5. Spring MVC 学习

    一.基础 Spring MVC是当前最优秀的MVC框架,自从Spring 2.5版本发布后,由于支持注解配置,易用性有了大幅度的提高.Spring 3.0更加完善,实现了对Struts 2的超越.现在 ...

  6. hdu 1541Stars

    题意:定义在某颗星星左下方的星星的个数表示该星星的水平,求出水平分别为为0...n-1的星星个数. 首先题目是按照y坐标升序输入的,设第第1,2...n个星星的横坐标依次为x1,x2,...xn.显然 ...

  7. mac xampp命令行调用mysql

    参考 http://www.cnblogs.com/machao/p/6206483.html 直接mysql不行,显示command not found 调用 sudo ln -s /applica ...

  8. 爬虫:网页里元素的xpath结构,scrapy不一定就找的到

    这种情况原因是html界面关联的js文件可能会动态修改DOM结构,这样浏览器完成了动态修改DOM,在 浏览器上看到的DOM结构,就和后台抓到的DOM结构不通 举例:新浪微博发的微博,在浏览器通过fir ...

  9. EasyMvc入门教程-基本控件说明(7)文字块导航

    文字块导航其实就是开发winform时候常见的 带Title的Group面板..~!@#¥..好吧,没开发过winform的同学看下图: 实现代码如下: @Html.Q().BlockField(). ...

  10. 微信小程序 - 单个题目

    后端传过来的数据,如果通过wx:for遍历出来那就是一个页面全部排下来.... 我的想法就是,页面初始化时设置一个默认值 1/50 就是 index+1 / 50(后端传过来的数组长度),通过控制in ...