本文主要内容

collections.namedtuple

__getitem__ 和 __len__

__repr__和__str__

__abs__、__add__和__mul__

__bool__

本文内容的表格式总结

语 法

调用的方法(按照顺序寻找)

备注

list[2]

__getitem__(2)

list[1:3:2]

__getitem__(slice(1,3,2))

切片时传入的参数是slice类型

for i in object:

__iter__()、__getitem__()

__iter__需要返回迭代器,并不断调用next()

in object

__contains__()、__iter__()、__getitem__()

__iter__()、__getitem__()会按照顺序搜索

print(object)

__str__()、__repr__()

if object:

__bool__()、__len__()

使用if、while等判断句时,会调用__bool__()

如果没有这两个方法,一般情况下,自定义的类总认为是真的

何为python的数据模型

本文所指的python数据模型,也可成为python中内置的对象模型(一切皆为对象),其包含的一些方法为特殊方法,在java中也称“魔术方法”。由于python文档里面喜欢使用“数据模型”这个词,所以本文依此称数据模型。

简单来说,数据模型就是python自有的数据类型,及其包含的特殊方法。例如:使用len()时会调用__len__特殊方法;使用list[]时会调用__getitem__方法;使用各类运算符也会调用其相对应的方法。从根本上而言,list[]、+、-、*、/、for i in x这些写法只是为了更简洁和更具有可读性,但内部跟其他操作一下,也是通过方法实现的,这就是特殊方法。

可命名元组(namedtuple)

#导入可命名元组

from collections importnamedtuple#创建的两种方法 (创建股票模型,每只股票包括name和price)

Stock_1= namedtuple("stock", ("name", "price")) #方法1:第二个参数传入可迭代对象(元组、数组等都可)

Stock_2= namedtuple("stock", "name price") #方法2:字符串之间用空格隔开

#生成多只股票

stock01 = Stock_1("SH000001", 1)

stock02= Stock_1("SH000002", 12)

stock03= Stock_1("SH000003", 123)

stock04= Stock_1("SH000004", 1234)#访问股票信息

print(stock01.name) #属性形式 SH000001

print(stock04[1]) #列表形式 1234

__getitem__ 和 __len__

1、__len__

classFoo:def __len__(self): #重写__len__方法

print("method __len__")return 1

if __name__ == "__main__":

foo=Foo()

n= len(foo) #使用len()时会自动调用__len__方法:method __len__

print(n) #1

2、__getitem__

from collections importnamedtuple

Stock= namedtuple("stock", ["name", "price"])classFoo:def __init__(self):

self._stock= [Stock(name, price) forname, pricein zip(range(1, 100), range(1, 100))]def __len__(self):returnlen(self._stock)def __getitem__(self, item):print(item)returnself._stock[item]if __name__ == "__main__":

foo=Foo()print(len(foo))print(foo[3]) #使用foo[3]时会调用__getitem__方法,解释器会将3传递给__getitem__(self, item)中的item参数

#stock(name=4, price=4)

print(foo[3:6]) #使用切片操作时也会调用__getitem__方法,解释器会传递slice(3, 6, None)item参数

#[stock(name=4, price=4), stock(name=5, price=5), stock(name=6, price=6)]

重写__getitem__后就可直接遍历对象:

if __name__ == "__main__":#此时可直接用for循环对foo进行遍历

for i infoo:print(i)#由于实现了__getitem__方法,foo实例就变成了可迭代对象

#不仅可以使用for循环正向迭代,也可反向迭代;还可以使用in判断

for i inreversed(foo):print(i) #反向迭代

print(Stock(name=2, price=2) in foo) #in判断会先调用__contains__方法,但是如果没有该方法,则调用__getitem__按顺序迭代搜索

#True (调用了2次getitem)

print(Stock(name=2, price=3) in foo) #False (调用了100次getitem方法,最后一次foo[99]发现不存在而停止迭代)

3、继续说说for i in x: 语句

刚刚我们使用for i in foo时发现可以正常迭代,如果在Foo类中重写__iter__方法,则无法正确迭代了:

from collections importnamedtuple

Stock= namedtuple("stock", ["name", "price"])classFoo:def __init__(self):

self._stock= [Stock(name, price) forname, pricein zip(range(1, 100), range(1, 100))]def __len__(self):returnlen(self._stock)def __getitem__(self, item):print(item)returnself._stock[item]def __iter__(self):pass

if __name__ == "__main__":

foo=Foo()for i in foo: #报错:TypeError: iter() returned non-iterator of type 'NoneType'

print(i)

如果我们把以上__iter__方法改成如下,那么又可使用for语句了:

def __iter__(self):

return iter(self._stock)

事实上我们在使用for i in foo语句时,会先调用__iter__方法,返回一个迭代器,然后for循环会不断使用next()进行遍历;如果foo里面没有该方法,则会调用__getitem__,并会从0开始依次读取相应的下标,直到发生IndexError为止,这是一种旧的迭代协议。

同样的,使用in判断时,解释器会依次寻找__contains__、__iter__、__getitem__方法。

from collections importnamedtuple

Stock= namedtuple("stock", ["name", "price"])classFoo:def __init__(self):

self._stock= [Stock(name, price) forname, pricein zip(range(1, 100), range(1, 100))]def __len__(self):returnlen(self._stock)def __getitem__(self, item):print(item)returnself._stock[item]def __iter__(self):returniter(self._stock)#def __contains__(self, item):

#print(item)

#return False

if __name__ == "__main__":

foo=Foo()for i in foo: #重写了__iter__(self)后解释器自动执行iter(foo)

print(i)

x= iter(foo) #手动执行

print(next(x)) #stock(name=1, price=1)

print(next(x)) #stock(name=2, price=2)

print(next(x)) #stock(name=3, price=3)

print(Stock(name=4, price=4) in foo) #按照__contains__、__iter__、__getitem__顺序寻找:True

__repr__和__str__

#接下来的例子引用自《流畅的python》#创建一个二维向量的类Vector,慢慢给它添加一些运算

classVector:def __init__(self, x=0, y=0):

self.x=x

self.y=ydef __repr__(self):return 'repr: Vector(%r, %r)' %(self.x, self.y)#def __str__(self): # 如果类中同时有__str__和__repr__,则调用print是会先使用__str__

#return "str: Vector(%r, %r)" % (self.x, self.y)

#这个类中现在只实现了__repr__方法

if __name__ == "__main__":

v= Vector(2, 3)print(v) #此时打印出来的不是这种形式

#打印出来的是Vector(2, 3)

#如果类中实现了__str__同样有此作用

#__repr__和__str__的区别在于,后者是在str()函数中被使用,或是在用print打印函数打印一个对象的时候才被#调用。如果你只想实现这两个特殊方法中的一个,__repr__是更好的选择,因为如果一个对象没有__str__函数#而python又需要调用它的时候,解释器会用__repr__作为代替

#故使用print()函数时,解释器会按照__str__、__repr__的顺序寻找

__abs__、__add__和__mul__

#接上面的二维向量的例子

from math importhypotclassVector:def __init__(self, x=0, y=0):

self.x=x

self.y=ydef __repr__(self):return 'Vector(%r, %r)' %(self.x, self.y)def __abs__(self): #abs本来是绝对值,在二维向量中指模

returnhypot(self.x, self.y)def __add__(self, other):

x= self.x +other.x

y= self.y +other.yreturnVector(x, y)def __mul__(self, scalar):return Vector(self.x * scalar, self.y *scalar)if __name__ == "__main__":

v= Vector(4, 3)#使用abs()求模,解释器自动调用__abs__方法

print(abs(v)) #5.0

#使用+求向量加法,解释器自动调用__add__方法

v2 = Vector(1, 5)print(v + v2) #Vector(5, 8)

#ps: __add__方法返回的是Vector对象,然后print函数会调用__repr__

#使用*求向量与数的乘法,解释器自动调用__mul__方法

print(v * 3) #Vector(12, 9)

#这里只实现了向量的数乘, 并且未实现 3*v

__bool__

#继续在上面列子中添加__bool__

from math importhypotclassVector:def __init__(self, x=0, y=0):

self.x=x

self.y=ydef __repr__(self):return 'Vector(%r, %r)' %(self.x, self.y)def __abs__(self):returnhypot(self.x, self.y)def __bool__(self):returnbool(abs(self))if __name__ == "__main__":

v= Vector(0, 3)if v: #调用__bool__

print(abs(v)) #3.0

#使用if或while语句,或者and\or\not运算符,为了判定一个对象v是真还是假,python会调用bool(v),这个函数只能返回True或者False#默认情况下,自定义的类的实例总被认为是真的,除非这个类对__bool__或者__len__函数有自己的实现。#bool(v)后面是调用v.__bool__()的结果;如果不存在__bool__方法,那么bool(v)会尝试调用v.__len__(),若返回0,则bool返回False,否则为True

#python 3.6的官方文档如下介绍

'''By default, an object is considered true unless its class defines either a __bool__() method that

returns False or a __len__() method that returns zero, when called with the object.

Here are most of the built-in objects considered false:

constants defined to be false: None and False.

zero of any numeric type: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)

empty sequences and collections: '', (), [], {}, set(), range(0)

Operations and built-in functions that have a Boolean result always return 0 or False for false

and 1 or True for true, unless otherwise stated. (Important exception: the Boolean operations or and and

always return one of their operands.)'''

python中的全部特殊方法

python中一共有83个特殊方法,其中47个用于算术运算、位运算和比较操作。我根据《流畅的python》中的整理,摘录如下两个表格

表1:跟运算符无关的特殊方法

类  别

方法名

字符串/字节序列表示形式

__repr__、__str__、__format__、__bytes__

数值转换

__abs__、__bool__、__complex__、__int__、__float__、__hash__、__index__

集合模拟

__len__、__getitem__、__setitem__、__delitem__、__contains__

迭代枚举

__iter__、__reversed__、__next__

可调用模拟

__call__

上下文管理

__enter__、__exit__

实例创建和销毁

__new__、__init__、__del__

属性管理

__getattr__、__getattribute__、__setattr__、__delattr__、__dir__

属性描述符

__get__、__set__、__delete__

跟类相关的服务

__prepare__、__instancecheck__、__subclasscheck__

表2:跟运算符相关的特殊方法

类  别

方法名和对应的运算符

一元运算符

__neg__ -、__pos__ +、__abs__ abs()

众多比较运算符

__lt__ 、__ge__>=

算数运算符

__add__ +、__sub__ -、__mul__ *、__truediv__  /、__floordiv__ //、

__mod__  %、__divmod__ divmod()、__pow__ **或pow()、__round__ round()

反向算数运算符

__radd__、__rsub__、__rmul__、__rtruediv__、__rfloordiv__、__rmod__、__rdivmod__、__rpow__

增量赋值算术运算符

__iadd__、__isub__、__imul__、__itruediv__、__ifloordiv__、__imod__、__ipow__

位运算符

__invert__ ~、__lshift__ <>、__and__ &、__or__ |、__xor__ ^

反向位运算符

__rlshift__、__rrshift__、__rand__、__rxor__、__ror__

增量赋值位运算符

__ilshift__、__irshift__、__iand__、__ixor__、__ior__

如何使用特殊方法:

1、特殊方法的调用是隐式的,通常你的代码无需直接使用特殊方法。除非有大量的元编程存在,直接调用特殊方法的频率应该远远低于你去实现它们的次数。唯一的例外可能是__init__方法,你的代码里可能经常会用到它,目的是在你的子类的__init__方法中调用超类的构造器。

2、通过内置的函数(例如len、iter、str等)来使用特殊方法是最好的选择。这些内置函数不仅会调用特殊方法,通常还提供额外的好处,而且对于内置的类来说,它们的速度更快。

3、不要自己想当然地随意添加特殊方法,比如__foo__之类的,因为虽然现在这个名字没有被python内部使用,以后就不一定了。

——《流畅的Python》

python高级系列文章目录

python的数据模型_python高级(一)—— python数据模型(特殊方法)相关推荐

  1. python generator长度_Python 高级特性之:生成器(generator)和迭代器(Iterator)

    前言: 之前学习Python自动化,接触了不少python的学习,对生成器印象尤其深,网上也看了很多介绍,下面主要是这些概念的个人学习整理(如侵删). 正文: 如要创建一个非常大的列表,受到内存限制, ...

  2. python app服务器_Python应用02 Python服务器进化

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! **注意,在Python 3.x中,BaseHTTPServer, SimpleH ...

  3. python的使用说明_Python教程:Python中__init__.py的使用用法说明

    Python中的Module是比较重要的概念.常见的情况是,事先写好一个.py文 件,在另一个文件中需要import时,将事先写好的.py文件拷贝 到当前目录,或者是在sys.path中增加事先写好的 ...

  4. python dicom 测量_python对DICOM图像的读取方法详解

    DICOM介绍 DICOM3.0图像,由医学影像设备产生标准医学影像图像,DICOM被广泛应用于放射医疗,心血管成像以及放射诊疗诊断设备(X射线,CT,核磁共振,超声等),并且在眼科和牙科等其它医学领 ...

  5. python数组展示_python 显示数组全部元素的方法

    python 显示数组全部元素的方法 如下所示: import numpy as np np.set_printoptions(threshold='nan') 以上这篇python 显示数组全部元素 ...

  6. python打印日历_python输出指定月份日历的方法

    python输出指定月份日历的方法 本文实例讲述了python输出指定月份日历的方法.分享给大家供大家参考.具体实现方法如下: #!/usr/bin/python import calendar ca ...

  7. python自动化库_Python操作自动化库PyAutoGUI的方法

    Python操作自动化库PyAutoGUI的方法 发布时间:2020-07-23 17:24:46 来源:亿速云 阅读:73 作者:小猪 这篇文章主要讲解了Python操作自动化库PyAutoGUI的 ...

  8. python 函数修饰_python修饰函数 python 函数有多个修饰符

    define的意思,用来定义函数. 如: def 函数名(参数1, 参数2, --, 参数N): 执行语句 # 例:简单的函数使用# 定义函数def hello(): print 'hello pyt ...

  9. python论文摘要_Python实现提取文章摘要的方法

    本文实例讲述了Python实现提取文章摘要的方法.分享给大家供大家参考.具体如下: 一.概述 在博客系统的文章列表中,为了更有效地呈现文章内容,从而让读者更有针对性地选择阅读,通常会同时提供文章的标题 ...

最新文章

  1. 关于中台的思考与尝试
  2. python中in的底层实现_python中print和input的底层实现
  3. Eigen矩阵的运算(二)
  4. 安徽计算机中专学校有哪些,安徽2021年中专学校里面都有什么专业
  5. c语言return 11,二级C语言教程章节测试11.对函数的进一步讨论
  6. CondenseNet总结
  7. php使用http请求头实现文件下载
  8. 使用静态容器防止并发修改同一对象
  9. 计算机科学常见工具书清单、项目开发清单
  10. 1、CSS 盒子模型,2、边框样式,3、CSS 轮廓(outline),
  11. 由深圳的大树所想到的
  12. windows NT的安全性
  13. 数据库之SQL更新语句中update set from用法
  14. 老Java程序员花两天做了个消消乐(天天爱消除)
  15. 截止失真放大电路_反馈/反馈电路/反馈类型的判别方法
  16. 天牛群,天牛须结合粒子群算法BAS-PSO。研究生阶段毕生所 学,低价出售!可定制pid参数整定。
  17. python箭头_箭头函数
  18. android中常见的异常总结
  19. .9图片报错Execution failed for task ':app:mergeDebugResources'. Crunching Cruncher scrollbar_thumb.9.p
  20. VS2015 还是VS2017 好用_强烈推荐:2020年12款Visual Studio 好用的工具

热门文章

  1. java后台代码添加超链接_Java 添加超链接至Excel文档
  2. Eclipse安装后启动出现error:could not create the java machine.
  3. Linux系统中源码包tomcat的管理
  4. java坐标代码_java实现计算地理坐标之间的距离
  5. 使用html-table模块生成html格式
  6. java telnet 交换机_华为交换机 telnet 配置(极简版)
  7. callback回调使用 vue_Vue 数据更新了但页面没有更新的 7 种情况汇总及延伸
  8. springboot 事务_第六章:springboot开启声明式事务
  9. 累加List对象中的某一个值
  10. MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist