类和对象:
我们经常会对打印一个对象来得到对象的某些信息。
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 ...
随机推荐
-
supermpa配置遇到的问题
环境 vs2010 supermap idesktop7.1.2 iobject7.1.2.net windowform 问题 在安装iobject7.1.2 64位时 在vs中的工具箱是不显示s ...
-
VJP1193 扫雷(状压)
链接 保存当前行和前一行两行的状态 #include <iostream> #include<cstdio> #include<cstring> #include& ...
-
PHP 递归实现层级树状展现数据
<?php $db = mysql_connect('localhost', 'root', 'root') or die('Can\'t connect to database'); mysq ...
-
jdbcTemplate批量插入处理数据
最近有个需求,就是批量处理数据,但是并发量应该很大,当时第一时间想到得是mybatis的foreach去处理,但是后来通过查资料发现,相对有spring 的jdbcTemplate处理速度,mybat ...
-
体验go语言的风骚式编程
最近想搞搞后台开发,话说注意力就转移到了公司用的golang.用Go做微服务比较方便,或许是因为golang强悍的语法吧,看到go的语法,自己已被深深的吸引.关于学习后台如何选择可以参考<做后台 ...
-
C#中Convert.ToInt32、int.TryParse、(int)和int.Parse四者的区别
Convert.ToInt32.(int)和int.Parse三者的区别: 首先:Convert.ToInt32 适合将object类类型转换成int类型,如Convert.ToInt32(sessi ...
-
Gitlab的安装汉化及问题解决
Gitlab的安装汉化及问题解决(2017/12/14目前版本为10.2.4) 一.前言 Gitlab需要安装的包太TM多了,源码安装能愁死个人,一直出错,后来发现几行命令就装的真是遇到的新大陆一样. ...
-
Codeforces Round #373 (Div. 2) B. Anatoly and Cockroaches 水题
B. Anatoly and Cockroaches 题目连接: http://codeforces.com/contest/719/problem/B Description Anatoly liv ...
-
JNotify的监测文件变化的简单测试例子
一.理由 使用JNotify监测的更全面,更快速. 二.参考代码 import net.contentobjects.jnotify.JNotify; import net.contentobject ...
-
【转】Android Studio打包全攻略---从入门到精通
原文地址:http://blog.csdn.net/zivensonice/article/details/51672846 初出茅庐 手动打包 怎么手动打包 项目写完了,现在需要把应用上传到市场,问 ...