Python学习笔记之面向对象编程(三)Python类的魔术方法
python类中有一些方法前后都有两个下划线,这类函数统称为魔术方法。这些方法有特殊的用途,有的不需要我们自己定义,有的则通过一些简单的定义可以实现比较神奇的功能
我主要把它们分为三个部分,下文也是分为这三个部分来讲解的
- 简单,功能性,一般不修改直接调用查看结果
- 实现简单功能,定义后使用
- 实现比较复杂功能,常常是一些我们常见类的特性的实现原理,具体分为
- 实例成为可迭代对象(列表的特性)
- 实例索引取值(列表的特性)
- 上下文管理(文件的特性)等
简单功能
这部分包括上面列出的前两个点
不需要修改直接调用的,主要有如下几个
- __dict__ 类和实例都可以调用这个方法
- 类调用返回这个类中已经定义了的属性和方法,包括特殊方法
- 实例调用返回属性的字典
- __module__ 类和实例都可以调用,类所在的模块,比如aa文件夹下的bb.py文件中则返回 aa.bb
- __class__ 只有实例可以调用,表明实例属于哪个类,内容包括了__module__的信息
- dir()函数 作用于类和实例上,返回它所有的属性和方法,实际上相当于调用了__dir__()函数
一般进行简单定义之后使用的方法
- __doc__ 返回定义类时标注的字符串,标注位置必须在定义的方法属性之前,默认是None
- __slots__ = ('name', 'age') 加一句这个可以只允许定义这两个属性,无法在实例中添加,这条命令只对当前类起作用,对子类无效
- __init__ 用于定义实例属性
- __call__ 输入 实例() 或者 类()() 触发,只有定义了这个,实例才可以像函数一样后面加括号
- __str__ print实例时打印出来的内容,不定义可以调用,重新定义后则可以定制打印内容
- __repr__ 直接输出实例名打印出来的内容,不定义可以调用,重新定义后则可以定制打印内容
- __new__ 创建实例时自动调用 __del__ 对象在内存中被释放时触发(后面不设置例子)
- __len__ 定义 len(实例) 返回的内容,比如字符串类就定义的是字符串的字符个数,当然也可以改成其他的
- __eq__ 改变==运算符的行为,定义实例使用==number时,是拿实例的什么与number相比
- 和eq类似的还有ne lt le gt ge
- 还有一些用于实例之间数值计算的 __add__ __abs__等方法,定义方式和__eq__差不多,这些应用的典型类就是数值类,定义这些其实定义了某些运算符的行为,比如__iadd__定义了+=的行为一样。除此之外还有转化为整数、浮点,
- __getattr__ 当实例访问的属性未被定义时,原来会报错,定义了这个之后就会按照这里定义的来输出. setattr 则可以设置属性 delattr则删除属性
下面是上面方法的使用展示
class Special:
'''描述类的信息,__doc__返回放在这里的字符串结果''' __slots__ = ('name', 'age','__weight') # 限制属性的取值 def __init__(self, name, age, weight):
self.name = name
self.age = age
self.__weight = weight def __call__(self, content): # 定义 实例() 会返回什么结果
print(content) def __str__(self): # 定义打印实例会返回什么结果
return 'Special object (name:%s)' % self.name __repr__ = __str__ # 这样简单赋值即可 def __len__(self): # 定义len函数返回的结果
return len(self.name) def __eq__(self, num): # 实例和数字比
return len(self.name) == num def __gt__(self, other): # 这样可以实现实例和实例比
return len(self.name) >= len(other) def __getattr__(self, attr):
if attr=='score':
return "You can't see the score"
创建实例
s = Special("Bob", 5, 4)
# s.hobby = "running" # 报错,因为__slots__限制了属性取值
s.__doc__ # 返回类定义时下方写的字符串描述内容
# '描述类的信息,__doc__返回放在这里的字符串结果'
s("__call__ is used") # 调用了__call__
# __call__ is used
print(s) # 调用__str__
# Special object (name:Bob)
s # 调用__repr__
# Special object (name:Bob)
len(s) # 调用了__len__
#
s==3 # 调用了__eq__
# True
Special("Mary", 4,5) > Special("Bob",5,4) # 调用__gt__
# True
s.score # 无score参数,调用__getattr__
# "You can't see the score" s.__dict__ # 要把__slots__注释掉才能看见属性的字典
# {'_Special__weight': 4, 'age': 5, 'name': 'Bob'}
s.__module__ # 查看所属模块
# '__main__'
s.__class__ # 查看所属类
# __main__.Special
dir(s) # 返回实例的所有属性和方法,调用了__dir__()方法
可迭代对象
使实例成为可迭代对象(可以被for循环的)
- 实现 __iter__ __next__ 方法
- 如果只实现__iter__则这个方法的返回值必须是一个迭代器
- 也可以__iter__返回一个self,再定义__next__方法,接受self为参数,在里面具体实现如何取得下一个值以及迭代器何时结束
- 原理是当对实例调用for循环时,相当于每次对__iter__的返回结果作用一次next()函数,所以要想迭代必须定义__iter__方法。第一种就是next每次正常调用__iter__返回的值,这就要求它的返回值是一个迭代器;第二种则是把next函数改掉,使其功能不再是找到下一个,而是定制我们想要的一些操作
第一种
class Ite1: def __init__(self, a):
self.a = a def __iter__(self):
return iter(range(2*self.a)) # iter函数将一个可迭代对象变成迭代器 i1 = Ite1(3)
for i in i1:
print(i) # 0到 5
第二种
class Ite2: def __init__(self, a, b):
self.a = a
self.b = b def __iter__(self):
return self def __next__(self):
self.a += 1
if self.a > self.b+1: # 条件成立则迭代器结束
raise StopIteration()
return self.a-1 for i in Ite2(2,5):
print(i) # 返回2-5
索引取值
这里实现使用中括号索引取值,或者像字典一样操作
- 实现 __getitem__方法
- 这个方法的参数除了self,还可以指定一个index,之后return一个和index相关的结果,其实相当于把实例定义成了一个函数,但是是用中括号调用的
- 结合 __setitem__ __delitem__ 即可让实例像字典一样操作
只定义__getitem__
class Index1: def __getitem__(self, index):
return 2*index # 如果定义和__next__中内容类似则实现既可以循环又可以[]取值了 i = Index1()
i[2] #
全部定义
class Index2: def __init__(self,**kw):
self.dict = kw def __getitem__(self, key):
return self.dict[key] def __setitem__(self, key, value):
self.dict[key] = value def __delitem__(self, key):
del self.dict[key] i = Index2(name="Bob")
i['name'] # 'Bob'
i['age'] = 13
i['age'] #
del i['age']
# i['age'] #报错,删掉就没有这个属性了
上下文管理
实现上下文管理,即可以和with结合使用
- 要实现 __enter__ __exit__ 两个方法
- __enter__会返回一个值,并赋值给as关键词之后的变量
- __exit__ 定义了处理结束后要做的事情,比如文件的关闭,socket的断开等
- 更深入地使用:__exit__中可以处理异常。
- 在上下文管理中运行的代码如果报错,会将三个值自动传入__exit__方法中,分别为 异常的类型,异常的值,异常的追踪栈
- 通过定义__exit__的返回值可以进行不同的处理,共有两种返回形式,返回True则这个异常忽略,返回None则正常抛出异常
简单实现上下文管理
class Manager: def __init__(self, text):
self.text = text def __enter__(self):
self.text = "It has started " + self.text
return self # 还是让这个类的实例进行下面的处理 def __exit__(self, ex_type, ex_value, ex_tb):
self.text = "It is over" with Manager("machine") as m:
print(m.text) print(m.text) # as定义的m仍然可以调用
# It has started machine
# It is over
# 发现最后执行了__exit__ 把这个属性改变了
异常处理
class DemoManager: def __enter__(self):
pass def __exit__(self, ex_type, ex_value, ex_tb):
if ex_type is IndexError:
print(ex_value.__class__)
return True
if ex_type is TypeError:
print(ex_value.__class__)
return # return None # 下面故意制造两种错误
with DemoManager() as nothing:
data = [1, 2, 3]
data[4] # raise IndexError, 该异常被__exit__处理了 with DemoManager() as nothing:
data = [1, 2, 3]
data['a'] # raise TypeError, 该异常没有被__exit__处理
参考
Python学习笔记之面向对象编程(三)Python类的魔术方法的更多相关文章
- python学习笔记(七):面向对象编程、类
一.面向对象编程 面向对象--Object Oriented Programming,简称oop,是一种程序设计思想.在说面向对象之前,先说一下什么是编程范式,编程范式你按照什么方式来去编程,去实现一 ...
- python 学习笔记7 面向对象编程
一.概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发"更快更好更强..." ...
- python学习笔记1 -- 面向对象编程高级编程1
说起高级其实也就是些基础的东西,但是活用和熟用肯定会大幅度提升代码质量 首先要记录的是面向对象的灵活性,及如何去控制其灵活性,她允许你在实例中新增属性和方法,允许你给类新增属性和方法,也支持在定义类时 ...
- python学习笔记1 -- 面向对象编程类和实例
由于之前有一定基础,所以python中的类的概接受的比较快,与其他语言一样, python也是通过类来进行事务的抽象,一切皆对象,要不然怎么说程序员不缺对象呢. 言归正传,python中类的声明是cl ...
- python自动化测试学习笔记-7面向对象编程,类,继承,实例变量,邮件
面向对象编程(OOP)术语: class TestClass(object): val1 = 100 def __init__(self): self.val2 = 200 ...
- Python学习笔记捌——面向对象高级编程
__slots__特殊变量的使用: 由于Python是动态语言,允许先编写类,然后在创建实例的时候添加属性或者方法:而__slots__特殊变量就是,限制往类里添加属性的: 在创建类的时候,使用__s ...
- python学习笔记六 面向对象相关下(基础篇)
面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可以将多函数中公用的变量封装到对象中) 对象,根据模板创建的 ...
- python学习笔记_week6_面向对象
面向对象 介绍(特性(class.object--->封装.继承,多态)).--->世界万物,皆可分类:世界万物,皆可对象 只要是对象,就肯定属于某种品类:只要是对象,就肯定有属性 你是上 ...
- python学习笔记(6)--面向对象学习
本节内容: 面向对象编程介绍 为什么要用面向对象进行开发? 面向对象的特性:封装.继承.多态 类.方法. 引言 你现在是一家游戏公司的开发人员,现在需要你开发一款叫做(人狗大战)的游戏,你就思 ...
随机推荐
- R数据可视化手册学习简单的绘制常见的图形
1.绘制散点图 # 使用ggplot2 library(ggplot2) ggplot(data = mtcars, aes(x = wt, y = mpg)) + geom_point() 2.绘制 ...
- HDFS体系结构(NameNode、DataNode详解)
hadoop项目地址:http://hadoop.apache.org/ NameNode.DataNode详解 (一)分布式文件系统概述 数据量越来越多,在一个操作系统管辖的范围存不下了,那么就分配 ...
- win10 64bit安装redis及redis desktop manager的方法
下载地址: MSOpenTech/redis——Github 下载后随便解压到一个地方 在 命令行 启动服务端 命令内容如下: redis-server.exe redis.windows.conf ...
- linux:echo命令示例
echo命令:用于字符串的输出 $echo string 1.打印普通字符串 $echo "hello kumata" hello kumata #这里的双引号完全可以省略,以下 ...
- linux UVC and hardware viewer
至于从哪个版本开始内核支持UVC,官方的话是“Linux 2.6.26 and newer includes the Linux UVC driver natively.” 1.查看摄像头ID: [r ...
- 一个JS Class的“增删改查”
function AA (){ var r={}; this.get = function(key){ return r[key]; } this.put = function(key,x){ r[k ...
- Closest Common Ancestors---poj1470(LCA+离线算法)
题目链接:http://poj.org/problem?id=1470 题意是给出一颗树,q个查询,每个查询都是求出u和v的LCA: 以下是寻找LCA的预处理过程: void LCA(u){ f ...
- extjs分页
1.本地分页:设置store的proxy属性为pagingmemoryproxy实例 2.远程分页
- Sqoop导入HBase,并借助Coprocessor协处理器同步索引到ES
1.环境 Mysql 5.6 Sqoop 1.4.6 Hadoop 2.5.2 HBase 0.98 Elasticsearch 2.3.5 2.安装(略过) 3.HBase Coprocessor实 ...
- [py][mx]django使用class写views-免去判断方法的烦恼
修改views使用class模式 类模式写views - 免去了函数模式的判断的烦恼 users/views.py from django.views.generic import View clas ...