python类的内置方法_python面向对象之类中的内置方法
__setattr__,__delattr__,__getattr__,__getattribute__以及标准类型的二次加工
__setattr__,__delattr__,__getattr__的用法
classFoo:
x=1
def __init__(self,y):
self.y=ydef __getattr__(self, item):#__getattr__只有在使用点调用属性且属性不存在的时候才会触发
print('----> from getattr:你找的属性不存在')def __setattr__(self, key, value):#__setattr__添加/修改属性会触发它的执行 将key的值改为value
print('----> from setattr')print({key:value})
self.__dict__[key] =valuedef __delattr__(self, item):#除属性的时候会触发__delattr__ item=删除的属性值
print('----> from delattr--%s'%item)
self.__dict__.pop(item)
f1=Foo('a') #触发了__setattr__#因为重写了__setattr__,凡是赋值操作都会触发它的运行,所以根本没赋值,除非直接操作属性字典,否则永远无法赋值
print(f1.__dict__)
f1.z=3
print(f1.__dict__) #添加属性也不可行
f1.xxx#_使用点调用属性且属性不存在的时候会触发 _getattr__
print(f1.__dict__)del f1.y #删除属性的时候会触发__delattr__
print(f1.__dict__)
二次加工标准类型(包装和授权)
包装
python提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
classList(list):def __init__(self,item,tag=False):
super().__init__(item)
self.tag=tagdefappend(self, object):#派生自己的append,加上判断
if notisinstance(object,str):raise TypeError('must be str')
super().append(object)
@propertydefget_mid(self):#增加自己的取中间数方法
index=len(self)//2
returnself[index]defclear(self):#派生自己的clear方法,加上限制
if notself.tag:raise TypeError('别乱删')
super().clear()
l1=List('hantao')print(l1)
l1.append('asdfd')print(l1)#l1.append(12) #抛异常
print(l1.get_mid)#l1.clear()#print(l1)
l1.tag=True
l1.clear()
授权
授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法
importtimeclassMyOpen(object):def __init__(self,file_path,MODE='r',encoding='utf-8'):
self.file=open(file_path,MODE,encoding=encoding)defwrite(self,line):#加入新的功能
t=time.strftime('%Y-%m-%d %T')
self.file.write('%s%s'%(t,line))def __getattr__(self, item):#默认功能授权给对象的默认属性
ifhasattr(self.file,item):returngetattr(self.file,item)raise TypeError('无此方法')
myopen=MyOpen('a.txt','w+')print(myopen.read)
myopen.write('ojbk\n')
myopen.write('jbok\n')
myopen.write('ijkb\n')
__getattribute__
classFoo:def __init__(self,x):
self.x=xdef __getattr__(self, item):print('执行的是我')#return self.__dict__[item]
def __getattribute__(self, item):print('不管是否存在,我都会执行')raise AttributeError('哈哈')
f1=Foo(10)
f1.x
f1.xxxxxx#当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError
二者同时出现
__setitem__,__getitem__,__delitem__
classFoo:def __init__(self,x):
self.x=xdef __setitem__(self, key, value):#以字典的形式改变或添加属性时触发
print('执行了setattr')
self.__dict__[key]=valuedef __getitem__(self, item):#以字典的形式调用属性时触发
print('执行了getattr')return self.__dict__[item]def __delitem__(self, item):#以字典的形式删除属性时触发
print('执行了delattr')
self.__dict__.pop(item)
foo=Foo('han')
foo['age']=100 #触发__setitem__
foo['x']='tao' #触发__setitem__
print(foo.__dict__)print(foo['x']) #触发__getattr__
del foo['x'] #触发__delattr__
__str__,__repr__,__format__
__str__,__repr__
改变对象的字符串显示
classPersion:def __init__(self,name,age):
self.name=name
self.age=agedef __str__(self):#访问实例化对象时返回的字符串
return '%s--str'%self.namedef __repr__(self):return '%s--repr'%self.name
hantao=Persion('hantao',18)'''str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常'''
print(hantao)print('来自str',str(hantao))print('来自repr',repr(hantao))
__format__
自定制格式化字符串
date_dic={'ymd':'{0.year}:{0.month}:{0.day}','dmy':'{0.day}/{0.month}/{0.year}','mdy':'{0.month}-{0.day}-{0.year}',
}classDate:def __init__(self,year,month,day):
self.year=year
self.month=month
self.day=daydef __format__(self, format_spec):if not format_spec or format_spec not indate_dic:
format_spec='ymd'fmt=date_dic[format_spec]returnfmt.format(self)
d1=Date(2016,12,29)print(format(d1))print('{:mdy}'.format(d1))
__slots__
1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__.
4.如何实现:当定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给
实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
5.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。
6.关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。更多的是用来作为一个内存优化工具。
classFoo:__slots__=['name','age']
f1=Foo()
f1.name='alex'f1.age=18
print(f1.__slots__)
f2=Foo()
f2.name='egon'f2.age=19
print(f2.__slots__)print(Foo.__dict__)#f1与f2都没有属性字典__dict__了,统一归__slots__管,节省内
__doc__
描述类的描述信息,无法被继承
classFoo:'我是描述信息'
pass
classBar(Foo):pass
print(Bar.__doc__) #该属性无法继承给子类
__module__,__class__
__module__ 表示当前操作的对象在那个模块
__class__表示当前操作的对象的类是什么
在test模块中建一个类:
classFoo:def __init__(self,x):
self.x=x
调用test模块中的类:
from test importFoo
foo=Foo('h')print(foo.__module__)print(foo.__class__)
结果:
test
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__
classFoo:def __del__(self):print('执行我啦')
f1=Foo()delf1print('------->')#输出结果
执行我啦------->
典型的应用场景:
创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放于内核空间内存中
当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源
这与文件处理是一个道理
f=open('a.txt') #做了两件事,在用户空间拿到一个f变量,在操作系统内核空间打开一个文件
del f #只回收用户空间的f,操作系统的文件还处于打开状态
#所以我们应该在del f之前保证f.close()执行,即便是没有del,程序执行完毕也会自动del清理资源,于是文件操作的正确用法应该是
f=open('a.txt')
读写...
f.close()
很多情况下大家都容易忽略f.close,这就用到了with上下文管理
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
classFoo:def __init__(self):pass
def __call__(self, *args, **kwargs):print('__call__')
obj= Foo() #执行 __init__
obj() #执行 __call__
__iter__,__next__(迭代器协议)
实现迭代器协议
classFoo:def __init__(self,x,stop):
self.x=x
self.stop=stopdef __iter__(self):returnselfdef __next__(self):if self.x >self.stop:raiseStopIteration
self.x+=1
returnself.x
f=Foo(5,10)print(next(f))
classFib:def __init__(self):
self._a=0
self._b=1
def __iter__(self):returnselfdef __next__(self):
self._a,self._b=self._b,self._a +self._breturnself._a
f1=Fib()print(f1.__next__())print(next(f1))print(next(f1))for i inf1:if i > 100:break
print('%s' %i,end='')
斐波那契数列
__get__,__set__,__delete__(描述符)
描述符的定义:
描述符本质是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
classFoo:def __get__(self, instance, owner):print('--get方法')def __set__(self, instance, value):print('--set方法')def __delete__(self, instance):print('--delete方法')
各方法的作用:
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)
classFoo:def __get__(self, instance, owner):print('--get方法')def __set__(self, instance, value):print('--set方法')def __delete__(self, instance):print('--delete方法')classTest:
x=Foo()def __init__(self,n):
self.x=n
f=Test('a') #此时会调用描述符
描述符的分类:
数据描述符:至少实现了__get__()和__set__()
非数据描述符:没有实现__set__()
注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
调用优先级:
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()
通过描述符机制来实现类型限制功能
classTyped():def __init__(self,name,expected_type):
self.name=name
self.expected_type=expected_typedef __set__(self, instance, value):print('set')if notisinstance(value,self.expected_type):raise TypeError('类型错误')
instance.__dict__[self.name]=valuedef __get__(self, instance, owner):print('get')if instance isNone:returnselfreturn instance.__dict__[self.name]def __delete__(self, instance):print('delete')
instance.__dict__.pop(self.name)classPeople:
name=Typed('name',str)
age=Typed('age',int)
hobbies=Typed('hobbies',list)def __init__(self,name,age,hobbies):
self.name=name
self.age=age
self.hobbies=hobbies
classTyped:def __init__(self,name,expected_type):
self.name=name
self.expected_type=expected_typedef __get__(self, instance, owner):print('get--->',instance,owner)if instance isNone:returnselfreturn instance.__dict__[self.name]def __set__(self, instance, value):print('set--->',instance,value)if notisinstance(value,self.expected_type):raise TypeError('Expected %s' %str(self.expected_type))
instance.__dict__[self.name]=valuedef __delete__(self, instance):print('delete--->',instance)
instance.__dict__.pop(self.name)def typeassert(**kwargs):defdecorate(cls):print('类的装饰器开始运行啦------>',kwargs)for name,expected_type inkwargs.items():
setattr(cls,name,Typed(name,expected_type))returnclsreturndecorate
@typeassert(name=str,age=int,salary=float) #有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
classPeople:def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salaryprint(People.__dict__)
p1=People('egon',18,3333.3)
结合类的装饰器进行使用
自定义property(待总结)
__enter__,__exit__(with方法和上下文管理协议)
以打来文件举例:
f=open('a.txt')
f.read()
f.close()||
||
||\/with open('a.txt') as f:
f.read()
上下文管理协议就是利用with语句,无需自己关闭以及打开的对象
with语句的实际是通过类中的__enter__,和__exit__实现的
classMyOpen:def __init__(self,name):
self.name=namedef __enter__(self):#with语句直接回执行enter方法,并将返回值赋值给as后边的变量
print('--enter方法')returnselfdef __exit__(self, exc_type, exc_val, exc_tb):#再with语句执行完毕前,触发exit方法
print('--exit方法')
with MyOpen('a.txt')as f:print('开始执行')
需要注意的是:
1.__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
2.如果exit返回值是True,with语句应错误终止时不会终止总程序
执行过程:
1.with obj ----> 触发obj.__enter__(),并拿到返回值---->as f 赋值给f
2.开始执行with中的语句
---没有异常:运行完毕后执行__exit__()
---出现异常:直接触发__exit__(),三个值(异常类型,异常值和追溯信息)
------如果__exit__返回值不是True,报出异常,程序中断
------如果__exit__返回值是True,吞掉异常,结束with语句,其他程序继续执行
3.__exit__的运行完毕就代表着整个with语句的结束
用途或者说好处:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
__new__
classA:def __init__(self):
self.x= 1
print('in init function')def __new__(cls, *args, **kwargs):print('in new function')return object.__new__(A, *args, **kwargs)
a=A()print(a.x)
python类的内置方法_python面向对象之类中的内置方法相关推荐
- python 类可以调用实例变量_python面向对象中类对象、实例对象、类变量、实例变量、类方法、实例方法、静态方法...
1. 类对象和实例对象 Python中一切皆对象,Python类本身也是一种对象,类定义完成后,会在当前作用域中定义一个以类名为名字的命名空间.类对象具有以下两种操作: 可以通过"类名()& ...
- python中常见的双下方法_python中常见的双下方法_python面向对象(5)__特殊双下方法...
双下方法 双下方法是开发python这个语言程序员用的,源码中使用的. 我们不能轻易使用双下方法.可能重新写object的源码,慎用!!! 双下方法特征:你不知道干啥了,就会触发某个双下方法 len ...
- python面向对象编程中方法和属性_Python面向对象编程中关于类和方法的学习笔记...
Python面向对象编程中关于类和方法的学习笔记 类与类方法是面向对象的编程语言中必不可少的特性,本文总结了Python面向对象编程中关于类和方法的学习笔记,需要的朋友可以参考下 类和实例 pytho ...
- python面向对象编程中_Python面向对象编程中关于类和方法
类和实例 python是一个面向对象的语言,而面向对象最重要的概念就是类和实例, 记得刚学习的时候不太理解这些概念,直到老师说了一句"物以类聚". 没错就是类, 归类 物以类聚 类 ...
- python对象点方法_python面向对象知识点疏理
面向对象技术简介 类:用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例.class 类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且在 ...
- python内置类型方法_python基础(一)内置类型及方法
python 内置类型主要包含7大类: 数字 序列 映射 文件 类 实例 异常 其中,最常用数据类型为序列 序列 python中包含7种内建序列 列表(list):由方括号构成,用逗号分隔项目: [a ...
- python类和对象详解_Python公开课 - 详解面向对象
前言 在C语言中,单纯通过结构化的函数也可以实现很好的软件,顺序思路比较好理解:而C++则以面向对象的思维来进行代码组织,通过定义对象.成员变量.成员函数.以封装.继承和多态等方式来更灵活处理业务逻辑 ...
- python类包含对象的个数_python类与对象各个算数运算魔法方法总结
1.python类与对象各个算术运算魔法方法总结: 2.各个魔法方法应用举例: 3.实例训练: (1)我们都知道在 Python 中,两个字符串相加会自动拼接字符串,但遗憾的是两个字符串相减却抛出异常 ...
- python类怎么实例化rnn层_Python backend.rnn方法代码示例
本文整理汇总了Python中keras.backend.rnn方法的典型用法代码示例.如果您正苦于以下问题:Python backend.rnn方法的具体用法?Python backend.rnn怎么 ...
最新文章
- Linux下DNS简单部署(主从域名服务器)
- 使用英伟达NeMo让你的文字会说话,零基础即可实现自然语音生成任务 | 附代码...
- iOS网络 POST模拟表单上传单个与多个文件(直接调用分类里的方法即可)
- 因为征信原因,买房的2万定金没了
- flink sql 部署_在FlinkSQL中使用SQL client时,如何使用 query配置?
- 没有残差连接的ViT准确率只有0.15%!北大华为提出用于ViT的增强 Shortcuts,涨点显著!...
- 数据结构期末复习之二叉排序树
- Flutter Icons 与 CupertinoIcons 的不一样的体验
- 高计算密度+低功耗!浪潮新一代高密度服务器SA5248M4横空出世
- 顺丰薪酬体系大曝光,看完感叹:太走心了,不服不行!
- 云计算学习笔记002---云计算的理解及介绍,google云计算平台实现原理
- 【ML小结5】决策树(ID3、C4.5、CART)
- 在IDEA中调试JavaScript代码
- 5、JSP面试题总结
- win7添加网页ftp服务器地址,win7添加ftp服务器地址
- 如何用CSS3画出一个立体魔方?
- linux 编译过程中acx_pthread.m4类错误解决办法
- 基于MATLAB的模拟信号AM、FM等调制与解调
- 深度学习模型DNN部署到安卓设备上全流程示例——{pytorch->onnx>ncnn->Android studio}
- topcoders 666
热门文章
- Tensorflow2实现人脸关键点检测算法PFLD——一个精度高,速度快,模型小的人脸关键点检测模型
- 这瓶普普通通的六神花露水,凭什么能卖到500块?
- 如何成为“一分钟经理人”?
- 什么是FTP服务?其主要功能是什么?其传输方式有哪些?
- VSCODE集成golang 巨坑
- 北方民族大学计算机科学与导论试题,2016秋计算机导论(北方民族大学 张春梅)...
- taobao.item.templates.get( 获取用户宝贝详情页模板名称 )
- 详解OpenCV的视频背景/前景分割(背景建模/前景提取)类cv::BackgroundSubtractorKNN,并利用它实现对道路监控视频前景/背景的提取
- MyCAT读写分离分库分表
- RS232不能通信的问题