类和对象:
我们经常会对打印一个对象来得到对象的某些信息。
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. linux压缩及vi操作

    一:Linux的压缩方式 1.tar cvf 对文件进行压缩,tar cvf+压缩文件完成的命名+需要压缩的文件 2,tar -tf +命名的压缩文件:表示查看目录里面的内容 3,tar -xf 解压 ...

  2. 写给Android App开发人员看的Android底层知识(7)

    (十二)ContentProvider (1)ContentProvider是什么? ContentProvider,简称CP. 做App开发的同学,尤其是电商类App,对CP并不熟悉,对这个概念的最 ...

  3. ProxySQL的相关维护说明

    背景: 前面的2篇文章MySQL ProxySQL读写分离使用初探和MySQL ProxySQL读写分离实践大致介绍了ProxySQL的使用说明,从文章的测试的例子中看到ProxySQL使用SQLIT ...

  4. sort命令详解

    1.工作原理: sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出. [rocrocket@rocrocket programmi ...

  5. OpenGL判断一个点是否可见

    关于OpenGL中判断一个点是否可见,可以分成两种情况讨论:点在2D空间中和3D空间中的时候.并且"在2D空间中"可以看作"在3D空间中"的特殊情况. 温馨提示 ...

  6. Eclipse debug 调试快捷键

    F3  跳到光标所在的类或方法(按Ctrl+鼠标左键同样可以实现这一功能) F5  进到函数的内部 F6  单步调试 F7  从函数中退出 F8  调到下一个断点(不能使用时应该是和有道词典的快捷键冲 ...

  7. cpp(第十七章)

    1.baseic_ostream<charT,traits>& write(const char_type *s,streamsize n),cout.write()第一个参数提供 ...

  8. Qt自定义标签按钮

    当你接触到Qt时,你会为它极为方便的跨平台方面感到吃惊,从而想尝试着使用Qt.渐渐地你会发现Qt自带的一些控件不能满足自己的需要,此时就需要我们自己定义一个属于自己的控件.总所周知,标签的风格设置类比 ...

  9. read命令读取用户输入

    read命令用于从终端或文件中读取用户输入,它读取整行输入,如果没有指定名称,读取的行被赋值给内部变量REPLY.read命令常用选项:-a,-p,-s,-t,-n 1.REPLY变量 $readhe ...

  10. [0] TFS 分支/标签

    比较常见的版本控制分支策略有三种:不稳定主干策略.稳定主干策略.敏捷发布策略. 下面是对这几种策略的摘录: 不稳定主干策略 使用用主干作为新功能开发主线,分支用作发布. 被广泛的应用于开源项目. 比较 ...