类和对象:
我们经常会对打印一个对象来得到对象的某些信息。
class pair:
    def __init__(self,x,y):
        self.x=x
        self.y=y
if __name__=='__main__':
    p=pair(3,4)
    print p
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
<__main__.pair instance at 0x01723B20>
得到的这个结果。Instance at 0x01723B20.这是对象在内存中的地址。这个对我们来说没啥作用,如何才能体现出对象的具体信息呢。有两种方法。__repr__和__str__.代码修改如下
class pair:
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def __repr__(self):
        return 'Pair({self.x},{self.y})'.format(self=self)
    def __str__(self):
        return '({self.x},{self.y})'.format(self=self)
那么__repr__和__str__的区别在哪里呢。看下下面的调用,命令行直接调用类实例的时候,是__repr__在起作用,如果是print 实例的时候则是__str__在起作用
>>>ret= pair(3,4)
>>>ret
>>>Pair(3,4)
>>>print ret
>>>(3,4)
 
 
 
 
让对象支持上下文协议。
说到上下文协议首先先介绍下with的用法。我们经常打开文件进行数据读取或者是更新。如下面的代码
f=open(r'E:\py_prj\test.txt','rb')
for line in f:
    print line
如果这时忘记了写f.close()或者说写了f.close()但是由于读取文件的中途出现错误。导致f.close()未执行。这个时候该怎么办呢。我们通常想到的是try…except语句。代码如下。不管是执行成功还是失败。最后finally中都会执行f.close()将文件关闭
try:
    f=open(r'E:\py_prj\test.txt','rb')
    for line in f:
        print line
except:
    print 'error'
finally
:
    f.close()
用try..except…finally倒是能规避掉异常带来的失误。但是代码稍显多了点。有没有可以简化的方法呢。With就是满足这个需求的。代码如下。
with open(r'E:\py_prj\test.txt','rb') as f:
    for line in f:
        print line
看上去貌似with也没有进行异常保护呢,如果出现前面的问题,会是什么样的结果呢。先来看下with的说明文档
while this might look like magic, the way Python handles with is more clever than magic. The basic idea is that the statement after with has to evaluate an object that responds to an __enter__() as well as an __exit__() function.
After the statement that follows with is evaluated, the __enter__() function on the resulting object is called. The value returned by this function is assigned to the variable following as. After every statement in the block is evaluated, the __exit__() function is called.
从上面的描述来看,with的使用和__enter__以及__exit__有关系。我们来自己测试一把,在类中运用with语句
class sample:
    def __enter__(self):
        print 'enter'
    def
__exit__(self,type,value,trace):
        print 'exit' if __name__=='__main__':
    s=sample()
    with s as test:
        print 'test sample'
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
enter
test sample
exit
从上面的执行顺序可以看到当执行到with s as test的时候,进入了__enter__,并打印enter。然后执行with中的具体语句打印test sample。在将with下面的语句执行完后就开始执行__exit__。这样的with的执行顺序就清楚了。在__exit__中有三个参数,type,value,trace。这是干什么用的呢。这是存储异常的一些消息。通过这3个参数可以得到执行失败的一些信息
 
关于__slots__
我们在类中定义的属性都是保存在一个字典中的。如果要查看类中的属性,直接查看__dict__就可以了
class date_try(object):
    def __init__(self):
        self.year=2017
        self.month=6
        self.day=12
if __name__=='__main__':
    d=date_try()
    print d.__dict__
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
{'month': 6, 'day': 12, 'year': 2017}
通过执行__dict__可以查看到全部的属性。如果我们中途还想绑定属性呢。
d=date_try()
d.hour=22  #在这里绑定了hour
print d.__dict__
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
{'month': 6, 'day': 12, 'hour': 22, 'year': 2017}
可以看到hour也加入到了__dict__中去了
有一种场景,如果我们有很多个类,但是每个类中都是固定的几个属性。如果都用dict来存储,就太浪费内存了,原因在流畅的python的学习笔记中介绍给,dict由于采用hash索引的方法,虽然查找速度快,但是很占内存。既然类中的属性固定。那么我们是否可以限定属性呢而且不用dict存储呢。这里就要用到__slots__
 
class date_try(object):
    __slots__=('year','month','day')
    def __init__(self):
        self.year=2017
        self.month=6
        self.day=12 if __name__=='__main__':
    d=date_try()
    print d.__dict__
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 32, in <module>
    print d.__dict__
AttributeError: 'date_try' object has no attribute '__dict__'
这个时候如果去查看__dict__就会报错,证明属性没有存储在__dict__中。这样只会给属性单独分配空间而不会用到dict。那如果我想增加属性呢
d=date_try()
d.hour=22
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 32, in <module>
    d.hour=22
AttributeError: 'date_try' object has no attribute 'hour'
是没法添加的。由于定义了__slots__,因此这个类中的属性就只能用__slots__中的属性名。除此之外的无法添加
如果有很多类且类的属性都固定,那么用__slots__的确可以达到节省内存的效果。但是缺点也显而易见,属性全部固定。无法添加。
 
8.5 在类中封装属性名
这一节介绍的是私有变量。我们先来看下什么是私有变量
class private(object):
    def __init__(self):
        self.__internal=0
        self.public=1
if __name__=='__main__':
    p=private()
    print p.__internal
在类private中定义了2个变量,__internal以及public。其中internal是以双下划线开头的。这种定义的变量就是私有变量。私有变量通过类属性以及子类都无法访问。我们来看下上面代码的执行结果:
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 54, in <module>
    print p.__internal
AttributeError: 'private' object has no attribute '__internal'
访问__internal失败,提示private对象没有__internal属性。其实python将私有变量进行了转换,转换成了__<类名><私有变量>。我们通过下面的打印来看下
print dir(private)
print dir(p)
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
 
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_private__internal', 'public'] 
可以看到print dir(p)中的变量变成了_private__internal.那么我们可以通过下面的方式访问:
p=private()
print p._private__internal
那么私有变量能否被子类所继承呢,来看下面的代码
class private(object):
    def __init__(self):
        self.__internal=0
        self.public=1 class private_child(private):
    def __init__(self):
        private.__init__(self)
        print 'private_child'
       
self.__internal+=2 if __name__=='__main__':
    c=private_child()
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 43, in <module>
    c=private_child()
  File "E:/py_prj/python_cookbook/chapter8.py", line 38, in __init__
self.__internal+=2
AttributeError: 'private_child' object has no attribute '_private_child__internal'
private_child
同样的提示无法访问。但是通过 self._private__internal是可以访问。从这里可以看到其实python不存在所谓的私有变量,只是把变量换了一种封装方式而已。
 
8.6 创建可管理的属性
这一节介绍了@property的用法。@property的作用主要有2个:
1 将类方法转换为只读属性
2 重新实现一个属性的setter以及getter方法。
我们分别来看下2个作用的用法,首先是第一个将类方法转换成只读属性
class property_try(object):
    def __init__(self,name):
        self.name=name
    def get_name(self):
        return self.name
if __name__=='__main__':
    p=property_try('zhf')
    print p.get_name()
在代码中,定义了一个name变量,并通过get_name函数来访问。在最后用p.get_name()来访问。我们将geg_name改成用属性的方法来调用
class property_try(object):
    def __init__(self,name):
        self.name=name
    @property
    def get_name(self):
        return self.name
if __name__=='__main__':
    p=property_try('zhf')
    print p.get_name
在get_name用@property修饰一下,get_name就变成了属性。用print p.get_name就可以访问了。既然可以访问了,那么我们可以进行赋值么
p.get_name='zhf1'
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 51, in <module>
    p.get_name='zhf1'
AttributeError: can't set attribute
运行失败,提示不能设置属性。那么这里就要用到我们的第二个方法。设置属性。
class property_try(object):
    def __init__(self,name):
        self.name=name
    @property
    def get_name(self):
        return self.name
    @get_name.setter
    def get_name(self,value):
        self.name=value
if __name__=='__main__':
    p=property_try('zhf')
    print p.get_name
    p.get_name='zhf1'
    print 'after reset,%s'
% p.get_name
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
zhf
after reset,zhf1
首先用@property装饰get_name,然后用@property.setter来装饰get_name.这样能就可以对get_name进行设置值了。那么@propery.setter的作用就是将一个只读属性变成了属性可赋值。
另外还有一个删除属性方法的deleter:
@get_name.deleter
def get_name(self):
    print 'failed'
当调用del p.get_name的时候将触发print ‘failed’

python cookbook第三版学习笔记十:类和对象(一)的更多相关文章

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

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

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

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

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

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

  4. python cookbook第三版学习笔记十四:类和对象(五)代理类以及内存回收

    代理类: 代理类的作用其实有继承有些类似,如果你想将某个实例的属性访问代理到内部另外一个实例中去,可以用继承也可以用代理.来看下代理的应用: class A:     def spam(self,x) ...

  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. MPP 二、Greenplum数据加载

    Loading external data into greenplum database table using different ways... Greenplum 有常规的COPY加载方法,有 ...

  2. centos 下 安装mysql

    今天在centos上安装了一下 mysql 出现了一点问题 记录一下解决方案: 1:解决yum install mysql-server没有可用包的问题 sudo yum install mysql- ...

  3. Java类的装载过程和静态代码块

    在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载.连接和初始化,其中连接又可以分成校验.准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下: ...

  4. Web设计思想——渐进增强

    最近在拜读一本Web体验相关的书<渐进增强--跨平台用户体验设计 >,阅读后做些总结,消化一下书中的精髓. 在阅读本文前,可以先思考下面几个问题. 1. 浏览网页的目的是什么? 2. 浏览 ...

  5. Python的初步认识与基本模块的导入

    由于公司开发都使用了Python,老大说要每个人都会,前端也要学,所以就看着老大写的博客一步步来了,但是对于小白而言,一门新的语言总得跳许多坑.尤其是Mac安装Python,各种坑. 坑一.由于Mac ...

  6. Akka(9): 分布式运算:Remoting-远程构建式

    上篇我们讨论了Akka-Remoting.我们说Akka-Remoting是一种点对点的通讯方式,能使两个不同JVM上Akka-ActorSystem上的两个Actor之间可以相互沟通.Akka-Re ...

  7. tomcat抬头有“选择”或“选定”,导致tomcat无法运行问题

    2. 遇到tomcat抬头有"选择"或"选定",导致tomcat无法运行问题 解决:在tomcat抬头右键--属性,去掉"快速编辑模式"勾选 ...

  8. PHP+MySql实现后台数据的读取

      我们使用的是PHP 的php_mysqli扩展   首先了解一些基础的用法  1.连接数据库使用 mysqli_connect()  参数:①主机地址 ②MYSQL用户名 ③MYSQL密码 ④选择 ...

  9. oracle sql语句跟踪及性能分析工具实现

    在网上找了一大圈,没找着合适的工具来跟踪oracle一段时间的sql. 我们的场景是打算自动化跑遍所有场景(rft)+fiddler跟踪请求+后端跟踪sql,根据结果去分析慢的请求和sql,本来awr ...

  10. php中的捕获异常操作

    <?php if(!isset($_SESSION)){ session_start(); } include '../common/mysql.class.php'; include '../ ...