python 面向对象进阶

参考:cnblogs.com/linhaifeng/articles/6204014.html

一.isinstance与issubclass
1.isinstance(obj,cls):判断对象obj是否为类cls的实例

class Foo(object):
    pass
f1=Foo()
print(isinstance(f1,Foo))   #True

子类的实例也是父类的实例:

class foo:
    pass
class bar(foo):
    pass
b1=bar()
print(isinstance(b1,bar))   #True
print(isinstance(b1,foo))   #True

2.issubclass(sub,super):判断类sub是否是类super的子类

class Foo():
    pass
class Bar(Foo):
    pass
print(issubclass(Bar,Foo))   #True

二.__ setattr__,__delattr __, __getattr __
__getattr __(self,item):在调用对象不存在的属性时运行
__ delattr __(self,item):在删除对象的属性时运行
__setattr __(self,key,value):在设置对象的属性时运行

class foo:
    def __init__(self,y):
        self.y=y
    def __getattr__(self,item):
        print('执行__getattr__')
    def __delattr__(self,item):
        print('执行__delattr__')
        #def self.item #触发无限递归
        self.__dict__.pop(item)
    def __setattr__(self,key,value):
        print('执行__setattr__')
        #self.key=value   #初始化结果:maximum recursion depth exceed
#初始化时需设置属性,__setattr__被触发,self.key=value时也是设置属性,再次被触发,发生递归
        self.__dict__[key]=value

f1=foo(10)
'''
print(getattr(f1,'y')) #10 #相当于print(f1.y)      
f1.sssssss #执行__getattr__
'''
'''
del f1.y #执行__delattr__
'''
'''
#初始化结果:执行__setattr__
print(f1.__dict__) #{'y':10}
'''

三.二次加工标准类型(包装)
1.包装:很多情况下需要基于标准数据类型来定制自己的数据类型,新增/改写方法,这用到了继承/派生

class List(list):
    def append(self,p_object):
        if type(p_object) is str:
            super().append(self,p_object)   #相当于list.append(self,p_object)
        else:
            print('只能添加str')
    def show_middle(self):
        mid_index=int(len(self)/2)
        return self[mid_index]

2.授权:更(geng1)新的方法都是由新类的某部分来处理,已存在的功能就授权给对象的默认属性—可理解为一种包装,不过是通过覆盖__getattr__实现(类似组合)而非通过继承/派生

import time
class Open:
    def __init__(self,filename,mode='r',encoding='utf-8'): 
        self.file=open(filename,mode,encoding=encoding)   
        self.mode=mode
        self.encode=encoding
    def write(self,content):
        t=time.strftime('%Y-%m-%d %X')
        self.file.write('%s%s'%(t,content))
    def __getattr__(self,item):
        return getattr(self.file,item)
        
f1=Open('a.txt','r+')
print(f1.read)   #获得read方法的内存地址   #read方法被封装进file,触发__getattr__
f1.write('系统崩溃')   #成功写入

四.__getattribute __(self,item)
1.在调用对象属性时被触发(不论该属性存在与否)

class foo:
    def __init__(self,x):
        self.x=x
    def __getattribute__(self,item):
        print('执行__getattribute__')
f1=foo(1)
f1.x   #执行__getattr__
f1.xx   #执行__getattr__

2.默认情况下,使用raise AttributeError(‘x’)调用__getattr__

#以下非默认情况下代码!!
class foo:
    def __init__(self,x):
        self.x=x
    def __getattr__(self,x):
        print('执行__getattr__')
    def __getattribute__(self,item):
        if 
        print('执行__getattribute__')
        raise AttributeError('抛出异常')
#模拟抛出异常,打印'AttributeError:抛出异常'
f1=foo(1)
f1.xx   #执行__getattribute__   执行__getattr__
f1.x   #执行__getattribute__   执行__getattr__

五.描述符(见描述符部分)

六.item系列:效果与__ **attr__相同,但使用的是字典形式
1.__getitem __(self,item):以字典形式查询item是否是对象self的属性时被触发
2.__setitem __(self,key,value):以字典形式给对象self添加key=value的属性时被触发
3.__delitem __(self,key):以字典形式删除对象self中的key属性时被触发

class foo:
    def __getitem__(self,item):
        return self.__dict__[item]
    def __setitem__(self,key,value):
        self.__dict__[key]=value
    def _delitem__(self,key):
        self.__dict__.pop(key)
f1=foo()
f1['name']='ale'        
print(f1['name'])   #ale
def f1['name']

七.__ str __, __repr __, __format __
1.改变对象的字符串显示:__str __ , __repr __(返回值必须为str)

class foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):   #print函数/str函数触发obj.__str__()
        return '名字是%s,年龄是%s'%(self.name,self.age)   #必须return值
f1=foo('alex',18)
print(f1)   #名字是alex,年龄是18   
#默认为<__main__.foo object at 0x000000000B5AF98>
class foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __repr__(self):   #交互式解释器/repr函数触发obj.__repr__()
        return '名字是%s,年龄是%s'%(self.name,self.age)
f1=foo('alex','18')
f1   #名字是alex,年龄是18
print(f1)   #名字是alex,年龄是18
#如果__str__没有被定义,会使用__repr__来代替输出

6种基本数据类型都有__ str__方法
在这里插入图片描述
注意,必须是交互式才会触发__repr __
在这里插入图片描述
2.自定制格式化字符串:a.__ format__(self,format_spec=’’)
format_spec用于自定义格式;默认为空字符串,此时为替换占位符

class date:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day
d1=date(2020,02,05)
x='{0.year}{0.month}{0.day}'.format(d1)   #调用d1.__format__()方法
print(x)   #20200205          #可扩展性差
format_dict={'ymd':'{0.year}{0.month}{0.day}','y:m:d':'{0.year}:{0.month}:{0.day}','m-d-y':'{0.month}-{0.day}-{0.year}'}
class date:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day
    def __format__(self,format_spec):
        if not format_spec:
            fm='ymd'
        elif format_spec not in format_dict:
            return '要求格式不存在'
        else:
            fm=format_dict[format_spec]
        return fm.format(self)   #必须返回str
d1=date('2020','02','05')
print(format(d1,'ymd'))

八.__ slots __—内存优化工具,也可防止用户给实例添加属性
1.一个类变量,变量值可以是list/tuple/iterator/str

定义__slots__后,其会为实例使用一种更紧凑的内部表示,实例通过一个很小的固定大小的数组来构建,而非为每个实例定义字典,__slots__中列出的属性在内部被映射到该数组的指定小标上

2.优点:字典会占用大量内存,如果有一个属性很少/实例很多的类,使用__slots__可节省内存
缺点:不能给实例添加新属性,只能使用__slots__中定义的属性

3.注意:__slots__很多特性依赖于普通的基于字典的实现;定义了__slots__的类不再支持一些普通类的特性(如多继承)—>只在经常使用的用作数据结构的类上使用

class Foo:
    #__slots__=['name','age']   #类似于属性字典{'name'=None,'age'=None}
    __slots__='name'
    
f1=Foo()   #实例不再具有__slots__属性/属性字典
f1.name='Ale'
print(f1.__slots__)   #找到类的__slots__属性
print(f1.name)   #Ale

九.__ next__和__ iter__实现迭代器协议
在这里插入图片描述
在这里插入图片描述

class foo:
    def __init__(self,n):
        self.n=n
    def __iter__(self):
        return self
    def __next__(self):
        if self.n>100:
            raise StopIteration('终止')   #抛出异常,打印StopIteration:终止
        self.n+=1
        return self.n
f1=foo(1)
print(f1.__next__())   #2
print(next(f1))   #3
for i in f1:
    print(i)   #成功循环
class fib_seq:
    def __init__(self):
        self.a=1
        self.b=1
    def __iter__(self):
        return self
    def __next__(self):
        self.a=self.b
        self.b=self.a+self.b
        return self.a
f1=fib_seq()
for i in f1:
    print(i)

十.__ doc__
1.返回文档注释

class foo:
    '我是描述信息'
    pass
print(foo.__doc__)   #我是描述信息

2.该属性无法被继承:每个类中如未定义自动加入’__ doc__=None’,且无法删除

class foo:
    '我是描述信息'
    pass
class bar(foo):
    pass
print(bar.__doc__)   #None

十一.__ module__和__class __
1.__ module__:返回当前操作的对象所在的模块

2.__ class__:返回当前操作的对象的类
在这里插入图片描述
在这里插入图片描述
十二.析构方法__del __
1.当对象在内存中被释放时自动触发执行

2.一般无需定义(python为高级语言,内存分配/释放交给解释器执行,该方法是由解释器在垃圾回收时自动触发执行)

class foo:
    def __init__(self,name):
        self.name=name
    def __del__(self):
        print('我执行啦')
        
f1=foo('alex')
'''
del f1.name
print('---')
#---     '我执行啦'   #文件执行完毕释放内存
'''
'''
def f1
print('---')
#'我执行啦'   ---   #回收实例占用的内存   
'''
  • 执行完毕为什么没有再回收一次

十三.__ enter__和__exit __
1.__enter __(self):执行with语句(实例化)时触发
返回值赋值给as后的变量名

2.__ exit__(self, exc_type, exc_val, exc_tb):with语句中代码全部执行完毕后/发生异常时触发—__exit __执行完毕代表with语句执行完毕

参数说明:三个参数分别为异常类型/异常值/追溯信息,无异常时均为None
在这里插入图片描述
在这里插入图片描述
注意:with语句中代码块出现异常,则with后的代码都无法执行

如果__exit__()返回True,那么异常会被清空,with后语句正常执行(但with语句内之后的代码不再执行)
在这里插入图片描述
在这里插入图片描述
用途:把代码块放入with中执行,with结束后,自动完成清理;在需要管理一些资源如文件,网络连接和锁的编程环境中,可在__exit__中定制自动释放资源的机制

3.上下文管理协议

with open('a.txt') as f:
    pass

上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法

class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
        # return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')

with Open('a.txt') as f:   #__enter__返回值赋值给f
    print('=====>执行代码块')
    # print(f,f.name)

4.模拟Open:

class Open:
    def __init__(self,filepath,mode='r',encoding='utf-8'):
        self.filepath=filepath
        self.mode=mode
        self.encoding=encoding

    def __enter__(self):
        # print('enter')
        self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        # print('exit')
        self.f.close()
        return True 
    def __getattr__(self, item):
        return getattr(self.f,item)

with Open('a.txt','w') as f:
    print(f)
    f.write('aaaaaa')
    f.wasdf #抛出异常,交给__exit__处理

十四.__ call__
对象名()/类名()()触发执行(需自行定义,否则不存在导致报错)

class foo:
    def __call__(self,*args,**kwargs):
        print('执行')
f1=foo()        
f1()   #执行

十五.元类metaclass:见元类部分

十六.重载
1.一些特殊方法:
在这里插入图片描述
在这里插入图片描述
2.每个运算符都对应了相应的方法:
在这里插入图片描述
2.重写上面的特殊方法,即实现了’运算符的重载’

class Person:
    def __init__(self,name,age):
        self.name=name
        self._age=age
    def __str__(self):
    #将对象转换成str,一般用于print方法
        return '名字是{0},年龄是{1}'.format(self.name,self._age)
    def __add__(self,other):
        if isinstance(other,Person):
            return self.name+other.name
        else:
            return '不是同类对象,不能相加'

p=Person('A',18)
q=Person('B',19)
print(p)
x=p+q
print(q)
#结果:
#名字是A,年龄是18
#A-B
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值