python基础——面向对象进阶下
python基础——面向对象进阶下
1 __setitem__,__getitem,__delitem__
把对象操作属性模拟成字典的格式
想对比__getattr__(), __setattr__() 和 __deltattr__()这三个通过属性的方式的三个方法
还有__getitem__(), __setitem__() 和 __delitem__()这三个函数, 是通过字典形式来处理属性
字典形式使用中括号的方式获取值
在实现__setitem__()的时候仍然需要使用__dict__来实现增值的设置
—getitem— 查看并返回一个value的值
- class Foo:
- def __init__(self,name):
- self.name=name
- def __getitem__(self, item): #需要一个返回值
- print('getitem')
- return self.__dict__[item] #返回一个值value的值
- f=Foo('egon')
- # print(f.name) #值是f.name="egon"
- print(f['name']) #触发getitem运行 把name传给item
- print(f.__dict__) #查看字典里面的值
输出结果为:
- getitem
- egon
- {'name': 'egon'}
__setitem__设置字典里面的值
- class Foo:
- def __init__(self,name):
- self.name=name
- def __setitem__(self, key, value):
- print('setitem')
- self.__dict__[key]=value
- f=Foo("egon")
- f["age"]=18 #触发 setitem 并打印setitem 并没有执行下面的值
- print(f.__dict__) #查看字典里面的值
输出结果为:
- setitem
- {'name': 'egon', 'age': 18}
__delitem__ 删除字典里面的值
- class Foo:
- def __init__(self,name):
- self.name=name
- def __delitem__(self, key):
- print('delitem')
- self.__dict__.pop(key)
- f=Foo('egon')
- # del f['age'] #del.f.age
- print(f.__dict__) #删除后打印一下
输出结果为:
- {'name': 'egon'}
2 _slots_
1.__slots__是什么:
是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.引子:
使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3.为何使用__slots__:
字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个.字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4.注意事项:
__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。
关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。更多的是用来作为一个内存优化工具。
slots_不会产生一个名称空间,省内存,属性只能设置_slots_规定的属性
- class People:
- _slots_=["name","age"] #可以加值
- p=People()
- p.name="karina" #对象没有自己的字典也就意味着没有自己的名称空间
- p.age="18"
- print(p.name,p.age)
输出结果为:
- karina 18
3 _iter_ _next_ 实现迭代器协议
可迭代对象是有方法__iter__()
迭代器是有方法__next__()
因而可以自己构建一个类, 使得它的对象, 既是一个可迭代对象, 也是一个迭代器
例1
- from collections import Iterable,Iterator #导入模块 判断是不是可迭代对象
- class Foo:
- def __init__(self,start):
- self.start=start
- def __iter__(self):
- return self
- def __next__(self):
- return 'asb'
- f=Foo(0)
- print(next(f)) #触发_next_ f._next_()
- for i in f: #res=f._iter_() #next(res)
- print(i)
- *目前这样的情况下会进入死循环
- # print(isinstance(f,Iterable)) #判断f是不是可迭代对象
- # print(isinstance(f,Iterator)) #判断f是不是迭代器
抛一个异常
- # from collections import Iterable,Iterator #导入模块 判断是不是可迭代对象
- # class Foo:
- # def __init__(self,start):
- # self.start=start
- #
- # def __iter__(self):
- # return self
- #
- # def __next__(self):
- # if self.start>10: #抛一个异常并 做一个判断
- # raise StopIteration
- # n=self.start #设定初始值 从0开始
- # self.start+=1 #每次自加一次
- # # return n
- # f=Foo(0)
- # print(next(f))
- # print(next(f))
- # print(next(f))
- # print(next(f))
- # for i in f:
- # print(i)
列2:模拟range功能
- class Range:
- def __init__(self,start,end):
- self.start=start
- self.end=end
- def __iter__(self):
- return self
- def __next__(self):
- if self.start>self.end:
- raise StopIteration
- n=self.start
- self.start+=1
- return n
- r=Range(0,2)
- for i in r :
- print(i)
输出结果为:
- 0
- 1
- 2
4 _doc_ 打印注释信息
在类中最开始定义的光秃秃的字符串是类的文档信息
查看该文档信息可以使用__doc__来获取
在函数中的第一个光秃秃的字符串也是, 通过函数名来调用__doc__即可获得
另外__doc__无法被继承
- class Foo:
- "我是描述信息"
- pass
- class Bar(Foo):
- pass
- print(Bar.__doc__) #该属性无法继承给子类
5 __module__
__module__和__class__是两个特殊属性
可以通过对象点的方式获取
__module__是获取对象所在模块的名字. __class__是获取对象所在的类
具体代码如下
- import time
- print(time.time.__module__)
- print(time.time.__class__)
- # time
- # <class 'builtin_function_or_method'="">
- </class>
6 __del__ 析构函数
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
- import time
- class Open:
- def __init__(self,filepath,mode='r',encode='utf8'):
- self.f=open(filepath,mode=mode,encoding=encode)
- def write(self):
- pass
- def __getattr__(self, item):
- return getattr(self,item)
- def __del__(self): #析构函数del
- print('---->del')
- self.f.close() #已删除就关闭文件 做清理操作
- f=Open('a.txt','r')
- del f #删除时 去执行__del__
- time.sleep(100)
输出结果为:
- ---->del
7 __enter__和__exit__
我们知道在操作文件对象的时候可以这么写
- 1 with open('a.txt') as f:
- 2 '代码块'
上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
- class Foo:
- def __enter__(self):
- print('enter')
- return "111"
- def __exit__(self, exc_type, exc_val, exc_tb):
- print('exit')
- print('exc_type',exc_type) #打印类型
- print('exc_val',exc_val) #打印值
- print('exc_tb',exc_tb) #打印追踪信息
- return True #返回一个不为假的布尔值,代表已经出来过异常,程序不会蹦掉
- # with Foo(): #res=Foo()._enter_
- # pass
- with Foo() as obj: #res=Foo()._enter_ #obj=res #with 触发_enter 然后执行打印拿回一个返回值
- print('with foo 的自代码块',obj)#再执行with的自代码块,打印的值为None
- #因为obj目前是没有值,如果有返回值,obj就会返回值
- raise NameError("名字属性定义") #主动抛出异常 触发 exit方法 在with的自代码中抛出异常,
- # 意味着with自代码块执行完,后面不管有没有代码都不执行
输入结果为:
- enter
- exit
- exc_type None
- exc_val None
- exc_tb None
- enter
- with foo 的自代码块 111
- exit
- exc_type <class 'NameError'>
- exc_val 名字属性定义
- exc_tb <traceback object at 0x02558058>
用途或者说好处:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处。
8 __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
- class People:
- def __init__(self,name):
- self.name=name
- def __call__(self, *args, **kwargs):
- print("call")
- p=People("egon")
- p() #属性直接加括号运行
输出结果为:
- call
9 元类
1、所有的对象都是由类产生的,类又是有type产生的
type--->类----->对象
type成为元类,是所有类的类,利用type模拟class关键字的创建类的过程
创建一个类两方面要素 一个是类的名字,一个是名称空间定制的属性
在python3里,所有的类都是新式类,都有继承object
type()手动创建一个类三点:#类名 字符串形式 #类继承关系
元祖形式 #类的属性名称空间 字典类型
- def run(self):
- print('%s is runing'%self.name)
- class_name='Bar' #类名
- bases=(object,) #类继承关系
- class_dic={
- "x":1, #类的属性名称空间
- "run":run
- }
- Bar=type(class_name,bases,class_dic)
- print(Bar)
输出结果为:
- <class '__main__.Bar'>
- class_name='Spam'
- bases=(object,)
- class_dic={
- "name":"karina",
- "age":18
- }
- Spam=type(class_name,bases,class_dic)
- print(Spam)
- print(Spam.__dict__)
输出结果为:
- <class '__main__.Spam'>
- {'name': 'karina', 'age': 18, '__module__': '__main__', '__dict__':
<attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}
2、自定义元类
可以写一个元类Mateclass, 它需要继承自type类
原来的类需要关联该元类, 也就是在继承中有 metaclass=元类名字
此时执行元类就可以生成一个对象, 也就是创建的这个类
基于此, 就是元类中的__init__()方法创建的 类对象, 所以新加的功能只需在__init__()方法中就行
元类的__init__()有额外三个参数, 分别是类名, 类基类, 类属性字典
实现检查__doc__的代码如下
- class MyMetaclass(type):
- def __init__(self, class_name, class_bases, class_dic):
- for key, value in class_dic.items():
- if callable(value) and not value.__doc__:
- raise Exception("{}方法内必须写入注释..".format(key))
- class Foo(metaclass=MyMetaclass):
- x = 1
- def __init__(self, name):
- self.name = name
- def run(self):
- 'run function'
- print('running')
- def go(self):
- print('going')
元类可以创建类的行为:
- type
- class Mymeta(type):
- def __init__(self,class_name,class_bases,class_dic):
- pass
- def __call__(self, *args, **kwargs):
- # print(self)
- obj=self.__new__(self) #产生空对象
- self.__init__(obj,*args,**kwargs) #obj.name='egon'
- return obj
- class Foo(metaclass=Mymeta):#指定元类等于Mymeta
- x=1
- def __init__(self,name):
- self.name=name #obj.name='egon 不能有返回值
- def run(self):
- print("running")
- f=Foo('egon')
- print(f)
python基础——面向对象进阶下的更多相关文章
- python基础——面向对象进阶
python基础--面向对象进阶 1.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 ...
- python基础-面向对象进阶
一.什么是反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被 ...
- Python 基础 面向对象之二 三大特性
Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...
- python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)
python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...
- python基础——面向对象编程
python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...
- python基础——面向对象的程序设计
python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- Python基础与进阶
1 Python基础与进阶 欢迎来到Python世界 搭建编程环境 变量 | 字符串 | 注释 | 错误消除 他只用一张图,就把Python中的列表拿下了! 使用 If 语句进行条件测试 使用字典更准 ...
- Python 3 面向对象进阶
Python 3 面向对象进阶 一. isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的 ...
- Python基础—面向对象(进阶篇)
通过上一篇博客我们已经对面向对象有所了解,下面我们先回顾一下上篇文章介绍的内容: 上篇博客地址:http://www.cnblogs.com/phennry/p/5606718.html 面向对象是一 ...
随机推荐
- 【前端单元测试入门05】react的单元测试之jest
jest jest是facebook推出的一款测试框架,集成了前面所讲的Mocha和chai,jsdom,sinon等功能. 安装 npm install --save-dev jest npm in ...
- ArrayList源码解析(JDK1.8)
package java.util; import sun.misc.SharedSecrets; import java.util.function.Consumer; import java.ut ...
- analyzing problems
If you talking to a friend or talking to a family member ,you can say:what's the metter or What's go ...
- Java枚举类使用
用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. p ...
- Maven-03: 优化依赖
已解析依赖: Maven会自动解析项目的直接依赖和传递性依赖,并且根据规则正确判断每个依赖的范围,对于一些依赖冲突,也能进行调节,以确保任何一个构件只有唯一的版本在依赖中存在.在这些工作之后,最后得到 ...
- Mycat 分片规则详解--范围分片
实现方式:切分规则根据文件(autopartition-long.txt)配置的范围来进行切片,制定基准列的取值范围,然后把这一范围的所有数据都放到一个DN上面 优点:适用于整体数量可知或总数量为固定 ...
- ELK学习笔记(一)安装Elasticsearch、Kibana、Logstash和X-Pack
最近在学习ELK的时候踩了不少的坑,特此写个笔记记录下学习过程. 日志主要包括系统日志.应用程序日志和安全日志.系统运维和开发人员可以通过日志了解服务器软硬件信息.检查配置过程中的错误及错误发生的原因 ...
- docker教程
Docker 包括三个基本概念 镜像(Image) 容器(Container) 仏库(Repository) 理解了返三个概念,就理解了 Docker 的整个生命周期. Docker 镜像 Docke ...
- Algorithm --> KMP算法
KMP算法 一.传统字符串匹配算法 /* * 从s中第sIndex位置开始匹配p * 若匹配成功,返回s中模式串p的起始index * 若匹配失败,返回-1 */ ) { ; || p.length( ...
- shell命令总结一
简述:这篇总结是在360企业安全实习第一周学到的. Linux中的 2>&1 .if文件命令 .tr .$0等相关参数含义的用法 1. 2>&1 command>/d ...