流畅python学习笔记:第十章:序列的修改,散列和切片
前面在介绍了类的很多内置方法,比如__add__,__eq__,这里继续介绍类的两个内置方法,这2个内置方法可以将一个类实例变成一个序列的形式。代码如下
class vector(object):
def __init__(self,components):
self._components=components
print self._components
def __len__(self):
return len(self._components)
def __getitem__(self,position):
return self._components[position] if __name__=="__main__":
v=vector([1,2,3])
print len(v)
print v[:3]
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter10.py
[1, 2, 3]
3
[1, 2, 3]
首先初始化的时候传入一个列表并赋值给_components。然后再调用len(v)的时候会自动调用__len__,返回_components的长度。调用v[1]或者v[0:3]的时候会调用__getitem__的方法,返回对应的_components的数据。
这里比较有意思的是,我们在__getitem__中我们返回的是self._components[position],这是代表position这个位置的元素。但是如果传递的是v[:3]的方式,也就是切片的方式,依然能够返回切片的结果。我们把代码修改下:
class vector(object):
def __init__(self,components):
self._components=components
print self._components
def __len__(self):
return len(self._components)
def __getitem__(self,position):
print type(position)
return position if __name__=="__main__":
v=vector([1,2,3])
print len(v)
print v[:3]
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter10.py
[1, 2, 3]
3
<type 'slice'>
slice(None, 3, None)
可以看到position的类型是slice,而且返回的是slice(None,3,None).那么slice是什么类型呢
Slice其实是个切片的对象。我们来看下用法
s=slice(0,2,1)
print a[s]
运行结果
[1, 2]
在这里slice(0,2,1)的原型是slice[start,stop,step].也就是说slice[0,2,1]其实是等于a[0:2]。看到这里我们就明白了。由于position是一个slice对象,且这个slice对象为slice(None, 3, None)因此结果也就等于self. _components[:3]
__getattr__和__setattr__方法:
首先来看下vector代码:
class vector(object):
shortcut_names="xyzt"
def __init__(self,components):
self._components=components
def __len__(self):
return len(self._components)
def __getitem__(self,position):
print type(position)
return position
def __str__(self):
return "vector"
def __getattr__(self, name):
cls=type(self)
print cls
if len(name) == 1:
pos=cls.shortcut_names.find(name)
if 0<=pos<=len(self._components):
return self._components[pos] if __name__=="__main__":
v=vector(range(1,10))
print "before add attribute %s" % v.__dict__ ⑴
print v.x ⑵
v.x=10 ⑶
print v.x
print "after add attribute %s" % v.__dict__ :⑷
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter10.py
before add attribute {'_components': [1, 2, 3, 4, 5, 6, 7, 8, 9]}
<class '__main__.vector'>
1
10
after add attribute {'_components': [1, 2, 3, 4, 5, 6, 7, 8, 9], 'x': 10}
首先在第一步的时候,v的属性只有一个列表。在第二步的时候print v.x。此时会检测v实例中是否有x属性,如果没有则会到类v.__class__中去寻找,如果仍然没找到,则会调用__getattr__方法。在__getattr__方法中,首先找到x在shortcut_names中的索引位置,然后根据这个索引找到_components中对应的数字。
在第三步的时候,我们设置了v.x=10.然后再打印v.x的时候,此时由于v.x=10导致v实例添加了x属性,因此不会调用__getattr__方法。查看v.__dict__也可以看到属性中新增了x属性。但这会导致一个问题,我们的目的是想通过x的索引位置得出_components对应位置的值,但是由于中途改变了x的值,导致我们在继续调用v.x的时候达不到我们的目的。因此有必要将这些在shortcut_names出现的值设置为可读。代码修改如下:
class vector(object):
shortcut_names="xyzt"
def __init__(self,components):
self._components=components
print self._components
def __len__(self):
return len(self._components)
def __str__(self):
return "vector"
def __getattr__(self, name):
cls=type(self)
if len(name) == 1:
pos=cls.shortcut_names.find(name)
if 0<=pos<=len(self._components):
return self._components[pos]
def __setattr__(self, name, value):
cls=type(self)
if len(name) == 1:
if name in cls.shortcut_names:
error="readonly attributes {attr_name!r}"
elif name.islower():
error="can't set attributes 'a' to 'z' in {cls_name!r}"
else:
error=''
if error:
msg=error.format(cls_name=cls.__name__,attr_name=name)
raise AttributeError(msg)
super(vector, self).__setattr__(name,value) if __name__=="__main__":
v=vector(range(1,10))
print v.x
v.x=10
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter10.py
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Traceback (most recent call last):
1
File "E:/py_prj/fluent_python/chapter10.py", line 39, in <module>
v.x=10
File "E:/py_prj/fluent_python/chapter10.py", line 31, in __setattr__
raise AttributeError(msg)
AttributeError: readonly attributes 'x'
新增__setattr__方法,当对属性进行赋值的时候,首先会调用__setattr__方法。在方法中对属性进行判断和保护。从执行结果来看,当执行v.x=10的时候。产生错误AttributeError: readonly attributes 'x'。这样就可以避免对x进行赋值了
最后来看一个__hash__的用法。还是以之前vector的例子,我们想要要用异或运算符依次计算各个分量的散列值。比如v[0]^v[1]^v[2].来看下代码实现:
class vector(object):
shortcut_names="xyzt"
def __init__(self,components):
self._components=components
def __len__(self):
return len(self._components)
def __str__(self):
return "vector"
def __getattr__(self, name):
cls=type(self)
if len(name) == 1:
pos=cls.shortcut_names.find(name)
if 0<=pos<=len(self._components):
return self._components[pos]
def __setattr__(self, name, value):
cls=type(self)
if len(name) == 1:
if name in cls.shortcut_names:
error="readonly attributes {attr_name!r}"
elif name.islower():
error="can't set attributes 'a' to 'z' in {cls_name!r}"
else:
error=''
if error:
msg=error.format(cls_name=cls.__name__,attr_name=name)
raise AttributeError(msg)
super(vector, self).__setattr__(name,value)
def __hash__(self):
hashes=(hash(x) for x in self._components)
print hashes
return reduce(operator.add,hashes) if __name__=="__main__":
v=vector(range(1,10))
print hash(v)
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter10.py
<generator object <genexpr> at 0x017B8148>
1
新增了__hash__方法。首先hashes得到各个向量值的hash值。然后通过reduce运算得到最终的异或值
这里简单介绍下reduce函数:
def add(x,y):
return x+y
a=[1,2,3,4,5]
print reduce(add,a)
E:\python2.7.11\python.exe E:/py_prj/fluent_python/chapter10.py
15
Reduce函数有2个参数值,第一个是执行函数,第二个是作用对象。例如reduce(fn,lst),fn首先会应用到第一对元素上,fn(lst[0],lst[1])生成一个结果r 然后fn会应用到r和下一个元素上,fn(r,lst[2]).依次按照这个方式进行调用,直到最后一个元素
流畅python学习笔记:第十章:序列的修改,散列和切片的更多相关文章
- python学习笔记(一)元组,序列,字典
python学习笔记(一)元组,序列,字典
- python 学习笔记1(序列;if/for/while;函数;类)
本系列为一个博客的学习笔记,一部分为我原创. 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 1. print 可以打印 有时需要 ...
- 流畅python学习笔记:第二十章:属性描述符:
在前面一章中介绍了@property的用法,但是存在一个问题,如果我有多个属性想转变成property特性,那不是针对每个都需要实现一个 @propery.setter 和 @property.get ...
- 流畅python学习笔记:第十四章:迭代器和生成器
迭代器和生成器是python中的重要特性,本章作者花了很大的篇幅来介绍迭代器和生成器的用法. 首先来看一个单词序列的例子: import re re_word=re.compile(r'\w+') c ...
- python 学习笔记(四) 统计序列中元素出现的频度(即次数)
案例一:在某随机序例中,找到出现频度最高的3个元素,它们出现的次数是多少? from random import randint # 利用列表解析器生成随机序列,包含有30个元素 data = [ra ...
- python 学习笔记12(序列常用方法总结)
http://www.cnblogs.com/vamei/archive/2012/07/19/2599940.html 多回想!!! 1. 序列(list,tuple,string) len(s) ...
- python学习笔记19(序列的方法)
序列包含有宝值 表(tuple)和表(list).此外,字符串(string)是一种特殊的定值表,表的元素可以更改,定值表一旦建立,其元素不可更改. 任何的序列都可以引用其中的元素(item). 下面 ...
- 流畅python学习笔记:第十一章:抽象基类
__getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...
- 流畅python学习笔记:第十五章:上下文管理器
在开始本章之前,我们首先来谈谈try-excep..final模块.在Python中,进行异常保护的最多就是用try..except..final.首先来看下下面的代码.进行一个简单的除法运算.为了防 ...
随机推荐
- Unity遮挡透明渐变
遮挡透明若没有渐变实现方法: 1.透明中物体存在list中 2.每过一段时间(可以每帧,但是流畅性会降低)摄像机发送一条射线向玩家,out hitInfo 3.list与hitInfo比对,将在lis ...
- Xmpp学习之Android-smack入门指导
Xmpp学习之Android-smack入门指导 版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请表明出处:http://www.cnblogs.com/cavalier-/p/69404 ...
- 一天搞定CSS:定位position--17
1.定位取值概览 2.相对定位relative <!DOCTYPE html> <html> <head> <meta charset="UTF-8 ...
- 【WPF】用三角形网格构建三维图形
虽然WPF只能支持部分三维模型,不过从应用功能开发的角度看,也已经够用了(非游戏开发).WPF 的三维图形,说得简单一点,也就两种而已. 1.把二维对象放到三维空间中,这个应该较为好办,像 Image ...
- DOUAudioStreamer 中kqueue的应用
DOUAudioStreamer是一个基于Core Audio的流式音频播放器,其中的DOUAudioEventLoop通过kqueue来控制音频的各种状态. kqueue简介(详情请看官方manua ...
- java之内部类
最近学了java,对内部类有一点拙见,现在分享一下 所谓内部类(nested classes),即:面向对象程序设计中,可以在一个类的内部定义另一个类. 内部类不是很好理解,但说白了其实也就是一个类中 ...
- dedecms 动态tab写法
项目要求要dedecms动态添加选项卡然后自己写了一个 现在需要些tab的栏目下创建子栏目 (如果是首页需要顶级栏目) 如图我在案例下添加了3个子栏目 然后每个子栏目里面添加需要在tab里面输出的内容 ...
- git 常用的命令符
1. linux操作命令: touch Filename:创建一个文件: mkdir 文件夹名字:创建一个文件夹: cd pathname:切换磁盘: cd ..:返回上一级: rm Filename ...
- mac os 安装PIP 及异常“”Can't install python module: PyCharm Error: “byte-compiling is disabled, skipping”“”的解决方案
For all who have the same problem, it took me a while to find the solution in a new installation of ...
- jquery 实现滚动条下拉时无限加载的简单实例
var lastId=0;//记录每一次加载时的最后一条记录id,跟您的排序方式有关. var isloading = false; $(window).bind("scroll ...