python cookbook第三版学习笔记十:类和对象(一)
类和对象:
我们经常会对打印一个对象来得到对象的某些信息。
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第三版学习笔记十:类和对象(一)的更多相关文章
- python cookbook第三版学习笔记十六:抽象基类
假设一个工程中有多个类,每个类都通过__init__来初始化参数.但是可能有很多高度重复且样式相同的__init__.为了减少代码.我们可以将初始化数据结构的步骤归纳到一个单独的__init__函数中 ...
- python cookbook第三版学习笔记十五:property和描述
8.5 私有属性: 在python中,如果想将私有数据封装到类的实例上,有两种方法:1 单下划线.2 双下划线 1 单下划线一般认为是内部实现,但是如果想从外部访问的话也是可以的 2 双下划线是则无法 ...
- python cookbook第三版学习笔记十二:类和对象(三)创建新的类或实例属性
先介绍几个类中的应用__getattr__,__setattr__,__get__,__set__,__getattribute__,. __getattr__:当在类中找不到attribute的时候 ...
- python cookbook第三版学习笔记十四:类和对象(五)代理类以及内存回收
代理类: 代理类的作用其实有继承有些类似,如果你想将某个实例的属性访问代理到内部另外一个实例中去,可以用继承也可以用代理.来看下代理的应用: class A: def spam(self,x) ...
- python cookbook第三版学习笔记十九:未包装的函数添加参数
比如有下面如下的代码,每个函数都需要判断debug的是否为True,而默认的debug为False def a(x,debug=False): if debug: print('calling a') ...
- python cookbook第三版学习笔记十八:可由用户修改的装饰器
定义一个属性可由用户修改的装饰器: 在前面的介绍中使用装饰器来包装函数,这一章来介绍下如何让用户调整装饰器的属性. 首先来看下代码: from functools import wraps,parti ...
- python cookbook第三版学习笔记二十:可自定义属性的装饰器
在开始本节之前,首先介绍下偏函数partial.首先借助help来看下partial的定义 首先来说下第一行解释的意思: partial 一共有三个部分: (1)第一部分也就是第一个参数,是一个函数, ...
- python cookbook第三版学习笔记六:迭代器与生成器
假如我们有一个列表 items=[1,2,3].我们要遍历这个列表我们会用下面的方式 For i in items: Print i 首先介绍几个概念:容器,可迭代对象,迭代器 容器是一种存储数据 ...
- python cookbook第三版学习笔记 一
数据结构 假设有M个元素的列表,需要从中分解出N个对象,N<M,这会导致分解的值过多的异常.如下: record=['zhf','zhf@163.com','775-555-1212','847 ...
随机推荐
- 细说"回车"和"换行"的故事
引言 最近在php还有c#以及memcache的shell当中经常看到\r\n的写法,刚开始还没注意, 不过后面感觉这样写有些不对头,\r表示回车 \n表示换行,那这样不是换行了两次吗? 为了解决疑 ...
- poj2069
poj2069 题意 求一个覆盖所有点的最小球体的半径.即求空间内一点到所有点的距离的最大值最小的点. 分析 模拟退火算法,但这道题竟然不用随机函数就能过了,主要体现了算法的渐近收敛性, 起始点随意取 ...
- python语言精粹《一》
第一章 静态语言:需要声明类型.变量不能改变类型! 动态语言:(也称脚本语言)主要的应用场景都是很短的应用程序(脚本),比如给静态语言编写的程序进行数据预处理.这样的程序通常也统称胶水代码. pyth ...
- 在.net下打造mongoDb基于官方驱动最新版本
还是一如既往先把结构图放出来,上上个版本添加了redis的缓存,但是不满足我的需求,因为公司有项目要求是分布式所以呢,这里我就增加了mongoDb进行缓存分布式,好了先看结构图. 总的来说比较蛋疼,因 ...
- 使用r.js来打包模块化的javascript文件
前面的话 r.js(下载)是requireJS的优化(Optimizer)工具,可以实现前端文件的压缩与合并,在requireJS异步按需加载的基础上进一步提供前端优化,减小前端文件大小.减少对服务器 ...
- 在Visual Studio for Mac中使用fastlane管理iOS的provision
Xamarin开发中,最烦的就是provision的管理了. 全手工的话,要先创建一个key,上传后生成cert文件,再创建provision.如果在手机上调试,还要把手机加到provision中去. ...
- 快来领取一场专门讲解UTF-8与UTF-16编码算法的GitChat活动的免费名额
微信扫一扫,可打开该GitChat活动页面 字符编码是计算机世界里最基础.最重要.最令人困惑的一个主题之一.不过,在计算机教材中却往往浮光掠影般地草草带过,甚至连一本专门进行深入介绍的专著都找不到(对 ...
- zookeeper 新手安装指南
Zookeeper集群的角色: Leader 和 follower (Observer) zk集群最好配成奇数个节点 只要集群中有半数以上节点存活,集群就能提供服务 本事例采用版本:zookee ...
- CentOS 安装数据库笔记
1.配置YUM源 # 下载mysql源安装包 shell.noarch.rpm # 安装mysql源 shell.noarch.rpm 检查mysql源是否安装成功 shell> yum rep ...
- java 多线程访问同一个对象数据保护的问题
java 多线程同时访问统一个数据的时候,会引起一些错误,后面的线程会修改数据,而前面的线程还在使用修改前的内容, 使用 synchronized 关键字,保证代码块只能有一个线程来访问 public ...