python_魔法方法(五):描述符和定制序列
描述符(property的原理)
描述符(descripto),用一句话来解释,描述符就是某种特殊的类的实例指派给另一个类的属性。那么什么是特殊类型的类呢?就是至少要在这个类中定义__get__()、__set__()、.__delete__()三个特殊方法中任意一个。
下面是描述符相关的魔法方法:
| 魔法方法 | 含义 |
| __get__(self,instance,owner) | 用于访问属性,它返回属性的值 |
| __set__(self,instance,value) | 将在属性分配操作中调用,不返回任何内容 |
| __delete__(self,instance) | 控制删除操作,不返回任何内容 |
举个例子
class MyDescriptor():
def __get__(self,instance,owner):
print("getting...",self,instance,owner)
def __set__(self,instance,value):
print("setting...",self,instance,value)
def __delete__(self,instance):
print("deleting...",self,instance) class Test():
x = MyDescriptor()
由于MyDescriptor实现了__get__()、__set__()、__delete__()方法,并且将它的类实例指派给Test类的属性,所以MyDescriptor就是所谓描述符类。到这里,有没有看到property()的影子。
实例化Test类,然后尝试对x属性进行各种操作,看看描述符类会有什么
>>> class MyDescriptor():
def __get__(self,instance,owner):
print("getting...",self,instance,owner)
def __set__(self,instance,value):
print("setting...",self,instance,value)
def __delete__(self,instance):
print("deleting...",self,instance) >>> class Test():
x = MyDescriptor() >>> test = Test()
>>> test.x
getting... <__main__.MyDescriptor object at 0x000000000301BEF0> <__main__.Test object at 0x0000000002F6AB00> <class '__main__.Test'>
当访问x属性的时候,python会自动调用描述符的__get__()方法,几个参数的内容分别是,self是描述符类自身的实例;instance是这个描述符的拥着者所在的类的实例,在这个里也就是Test类的实例化;owner是这个描述符的拥有者所在的类本身。
>>> test.x = "X - abc"
setting... <__main__.MyDescriptor object at 0x000000000301BEF0> <__main__.Test object at 0x0000000002F6AB00> X - abc
对x属性进行赋值操作的时候,python会自动调用__set__()方法,前两个参数跟__get__()方法是一样的,最后一个参数value是等号右边的值。
最后一个del操作也是同样的道理:
>>> del test.x
deleting... <__main__.MyDescriptor object at 0x000000000301BEF0> <__main__.Test object at 0x0000000002F6AB00>
只要弄清楚描述符,那么property的秘密就不再是秘密了!property事实上就是一个描述符类。
class MyProperty:
def __init__(self, fget=None, fset=None, fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, instance, owner):
return self.fget(instance)
def __set__(self, instance, value):
self.fset(instance, value)
def __delete__(self, instance):
self.fdel(instance) class C:
def __init__(self):
self._x = None
def getX(self):
return self._x
def setX(self, value):
self._x = value
def delX(self):
del self._x x = MyProperty(getX, setX, delX)
下面说一个实例,先定义一个温度类,然后定义两个描述符类用于描述摄氏度和花摄氏度两个属性。两个属性会自动进行转换,也就是说,你可以给摄氏度这个属性赋值,然后打印花摄氏度属性是自动转换后的结果.
>>> class Celsius():
def __init__(self,value=26.0):
self.value = float(value)
def __get__(self,instance,owner):
return self.value
def __set__(self,instance,value):
instance.cel = float(value) >>> class Fahrenheit():
def __get__(self,instance,owner):
return instance.cel * 1.8 +
def __set__(self,instance,value):
instance.cel = (float(value)-)/1.8 >>> class Temperature():
cel = Celsius()
fan = Fahrenheit() >>> temp = Temperature()
>>> temp.cel
26.0
>>> temp.fan
78.80000000000001
定制序列
无规矩不成方圆,任何事物都有属于自己的规律,轴遵照属于自己的规律,事情才能朝向自己意向的方向发展。所以介绍定制容器,要想成功的实现容器定制,需要先说一下协议。协议(protocols)与其他编程语言中的接口很相似,它规定哪些地方必须要定义。然后,在python中的协议就显得不那么重要,事实上,在python中,协议更像是一种指南。
在python中,像序列类型(如列表、元组、字符串)或映射类型(如字典)都是属于容器类型。接下来说一下定制容器,那就必须要知道,定制容器有关的一些协议;
如果说你希望定制的容器是不可改变的话,你只要定义__len__()、__getitem__()方法。
如果你希望定制的容器是可变的话,除了__len__()、__getitem__()方法,还需要定义__setitem__()、__delitem__()两个方法。
下面列举了定制容器类型相关的魔法方法及含义。
| 魔法方法 | 含义 |
| __len__(self) | 定义被len()函数调用时的行为(返回容器中元素个数) |
| __getitem__(self,key) | 定义获取容器中指定元素的行为,相当于self[key] |
| __setitem__(self) | 定义设置容器中指定元素的行为,相当于self[key] |
| __delitem__(self) | 定义删除容器中指定元素的行为,相当于del self[key] |
| __item__(self) | 定义当迭代容器中的元素的行为 |
| __reversed__(self) | 定义当被reversed()函数调用时的行为 |
| __contains__(self) | 定义当使用成员测试运算符(in或not in)时的行为 |
是视乎展现你的技术了,可以动手编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。
class CountList():
def __init__(self,*args):
self.values = [x for x in args]
self.count = {}.fromkeys(range(len(self.values)),0)
#这里使用列表的下标注作为字典的键,注意不能用元素作为字典的键
#因为列表的不同下标可能有值一样的元素,但字典不能有两个相同的键
def __len__(self):
return len(self.values)
def __getitem__(self,key):
self.count[key] += 1
return self.values[key] c1 = CountList(1,3,5,7,9)
c2 = CountList(2,4,6,8,10)
print(c1[1])
print(c2[1])
print(c1[1] + c2[1])
print(c1.count)
print(c2.count)
打印结果:
3
4
7
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
python_魔法方法(五):描述符和定制序列的更多相关文章
- Python笔记(二十五)_魔法方法_描述符
描述符的属性方法 __get__(self, instance, owner): 用于访问属性,返回属性的值 __set__(self, instance, value): 用于给属性赋值时,返回属性 ...
- 课时46:魔法方法:描述符(property的原理)
目录: 一.描述符(property的原理) 二.课时46课后习题及答案 ********************************** 一.描述符(property的原理) ********* ...
- 零基础学习python_魔法方法(41-48课)(迭代器)
接下来这个为啥要叫魔法方法呢,额,这个嘛我是跟小甲鱼的视频取的名字一样的,因为会讲比较多杂的东西,有... 魔法方法详细阅读地址:http://bbs.fishc.com/thread-48793-1 ...
- 利用描述符自定制property
利用描述符自定制property class Lazyproperty: def __init__(self,func): # print('==========>',func) self.fu ...
- Python之路(第二十七篇) 面向对象进阶:内置方法、描述符
一.__call__ 对象后面加括号,触发执行类下面的__call__方法. 创建对象时,对象 = 类名() :而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()( ...
- 【Python046--魔法方法:描述符】
一.描述符的定义: 描述符就是将特殊类型的类的实例指派给另外一个类的属性 1.举例: 特殊类型的类要实现以下三个方法中的其中一个或者全部实现 * __get__(self,instance,owner ...
- python_魔法方法(三):__str__()和__repr__()
使用python的魔法方法和time模块定制一个计时器的类 1.用time模块里的localtime()方法获取时间2.time.localtime返回struct_time格式3.表现你的类:__s ...
- python_魔法方法(二):算术运算
python2.2之后,对类和类型做了同意,将int().float().str().list().touple()这些BIF转换为工厂函数 >>> type(len) <cl ...
- python 面向对象专题(十):特殊方法 (三)__get__、__set__、__delete__ 描述符(三)方法是描述符
在类中定义的函数属于绑定方法(bound method),因为用户定义的函数都有 __get__ 方法,所以依附到类上时,就相当于描述符.示例 20-13 演示了从 面向对象专题(九)示例 20-8 ...
随机推荐
- 检测 iOS 的 APP 性能的一些方法
本文转载于微信公众号:iOS大全 首先如果遇到应用卡顿或者因为内存占用过多时一般使用Instruments里的来进行检测.但对于复杂情况可能就需要用到子线程监控主线程的方式来了,下面我对这些方法做些介 ...
- delete操作符
delete操作符通常用来删除对象的属性: Js代码 var o = { x: 1 }; delete o.x; // true o.x; // undefined 而不是一般的变量: Js代 ...
- (转)python set 用法
转载自:http://hi.baidu.com/����_xu/blog/item/5b9650c513bd3f049d163d8b .html python的set和其他语言类似, 是一个 基本功能 ...
- PopupWindow --- 弹出底部窗体
第一步 : 布局文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:a ...
- php学习笔记-变量的作用域
这个东西很难理解,但很重要,我觉得非常容易出错. PHP中的变量按照作用域分为有两种,一种是global,一种是local. 函数内部声明的变量就叫local型变量,只能在函数内部被访问到.一句话,l ...
- p2341&bzoj1051 受欢迎的牛
传送门(洛谷) 传送门(bzoj) 题目 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这 种关系是具有传递性的,如果A认为B受欢迎,B认为C ...
- Luogu 2258 [NOIP2014] 子矩阵
被普及组虐了,感觉
- Luogu 2839 [国家集训队]middle
感觉这题挺好的. 首先对于中位数最大有一个很经典的处理方法就是二分,每次二分一个数组中的下标$mid$,然后我们把$mid$代回到原来的数组中检查,如果一个数$a_{i} \geq mid$,那么就把 ...
- 15.Nginx 解析漏洞复现
Nginx 解析漏洞复现 Nginx解析漏洞复现. 版本信息: Nginx 1.x 最新版 PHP 7.x最新版 由此可知,该漏洞与Nginx.php版本无关,属于用户配置不当造成的解析漏洞. 使用d ...
- opencv头文件
转载自:http://blog.csdn.net/aaron121211/article/details/51526901 1. .hpp文件是.h和.cpp文件在一起的2. #include < ...