• Python开发基础----反射、面向对象进阶


    isinstance(obj,cls)和issubclass(sub,super)

    isinstance(obj,cls)检查是否obj是否是类 cls 的对象,如果是返回True

    1 class Foo(object):
    2     pass
    3 obj = Foo()
    4 print(isinstance(obj, Foo))

    issubclass(sub, super)检查sub类是否是 super 类的派生类,如果是返回True

    1 class Foo(object):
    2     pass 
    3 class Bar(Foo):
    4     pass
    5 issubclass(Bar, Foo)

    反射

    反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

    python面向对象中的反射:通过字符串的形式操作对象相关的属性。而python中的一切事物都是对象,即都可以使用反射。

    示例代码:

    1 class Teacher:
    2     school='jialidun'
    3     def __init__(self,name,age):
    4         self.name=name
    5         self.age=age
    6     def teach(self):
    7         print('%s teach' %self.name)

    通过字符串的方式判断是否存在一个属性:

    1 t=Teacher('bob',18)
    2 print(hasattr(Teacher,'name'))  #False
    3 print(hasattr(Teacher,'school'))    #True
    4 print(hasattr(Teacher,'teach'))     #True
    5 print(hasattr(t,'name'))  #True
    6 print(hasattr(t,'school'))    #True
    7 print(hasattr(t,'teach'))     #True

    通过字符串的方式获取一个属性:

    1 print(getattr(Teacher,'school'))    #获取到则返回属性的值
    2 print(getattr(Teacher,'sdfad',None))    #获取不到返回None,如果不指定None那么抛出异常错误

    通过字符串的方式设定一个属性:

    1 setattr(Teacher,'sex','male')    #设定Teacher类的属性sex='male'
    2 setattr(t,'sex','female')    #设定对象t对象的属性sex='female'
    3 print(Teacher.__dict__)
    4 print(t.__dict__)

    通过字符串的方式删除一个属性:

    1 delattr(Teacher,'sex')
    2 delattr(t,'sex')

    反射应用场景:用户交互

     1 class Cmd:
     2     def __init__(self,name):
     3         self.name=name
     4     def run(self):
     5         while True:
     6             cmd=input('>>>').strip()
     7             if not cmd:continue
     8             if hasattr(self,cmd):    #判断这个类包含不包含输入的属性
     9                 func=getattr(self,cmd)    #如果包含,获取该属性
    10                 func()    #执行该属性(输入name会抛错提示字符串不能被调用,因为name是一个数据属性,而非函数属性)
    11             else:
    12                 print('not valid func')
    13     def ls(self):
    14         print('ls function')
    15     def pwd(self):
    16         print('pwd function')
    17     def cat(self):
    18         print('cat function')
    19 c=Cmd('bob')
    20 c.run()

    反射的好处

    实现可插拔机制:可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,即可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

    动态导入模块:基于反射当前模块成员

    __str__方法

    改变对象的字符串显示

     1 class Teacher:
     2     def __init__(self,name,age):
     3         self.name=name
     4         self.age=age
     5 t=Teacher('bob',18)
     6 print(t)
     7 输出结果
     8 <__main__.Teacher object at 0x0000020FC4DA9278>
     9 
    10 #########分割线君###########
    11 
    12 class Teacher:
    13     def __init__(self,name,age):
    14         self.name=name
    15         self.age=age
    16     def __str__(self):
    17         return '<name:%s age:%s>' % (self.name, self.age)
    18 t=Teacher('bob',18)
    19 print(t)    #t.__str__()
    20 输出结果:类中的__str__函数的执行结果
    21 <name:bob age:18>

    __del__方法

    在程序执行完了之后会自动执行的内容

     1 class Foo:
     2     def __init__(self,x):
     3         self.x=x
     4     def __del__(self):
     5         print('执行__del__')
     6         '''一般用来做一些关于对象执行完了之后剩下的垃圾的清理操作'''
     7 f=Foo(10)
     8 print('执行完了')
     9 
    10 输出结果:先执行最后的print,没有代码了执行__del__函数
    11 执行完了
    12 执行__del__

    删除对象后立即执行的内容

     1 class Foo:
     2     def __init__(self,x):
     3         self.x=x
     4     def __del__(self):
     5         print('执行__del__')
     6         '''做一些关于对象的清理操作'''
     7 f=Foo(10)
     8 del f     #删除的时候也会执行del内容
     9 print('执行完了')
    10 
    11 输出结果:删除了f对象后执行了__del__后才执行最后的print
    12 执行__del__
    13 执行完了

    item系列

    以中括号的方式进行处理类似于:

    1 l=['a','b','c']
    2 dic={'a':1}
    3 print(l[1])
    4 print(dic['a'])

    __getitem__、__setitem__、__delitem__

     1 class Teacher:
     2     def __init__(self,name,age,sex):
     3         self.name=name
     4         self.age=age
     5         self.sex=sex
     6     def __getitem__(self, item):    #查询
     7         # return getattr(self,item)
     8         return self.__dict__[item]
     9     def __setitem__(self, key, value):    #设置
    10         # setattr(self,key,value)
    11         self.__dict__[key]=value
    12     def __delitem__(self, key):    #删除
    13         # delattr(self,key)
    14         self.__dict__.pop(key)
    15 f=Teacher('bob',18,'male')
    16 print(f.name) #f['name']
    17 print(f['name'])    #查询
    18 f['name']='bob_nb'    #设置
    19 print(f.__dict__)
    20 del f['name']    #删除
    21 print(f.__dict__)

    __len__方法

    给对象提供len()统计方法

    1 class Teacher:
    2     def __init__(self,name,age,sex):
    3         self.name=name
    4         self.age=age
    5         self.sex=sex
    6     def __len__(self):    #长度设置为10
    7         return 10
    8 f=Teacher('bob',18,'male')
    9 print(len(f))    #输出10

    其他方法(补充)

    __setattr__,__delattr__,__getattr__方法

     1 class Foo:
     2     x=1
     3     def __init__(self,y):
     4         self.y=y
     5     def __getattr__(self, item):
     6         print('----> from getattr:你找的属性不存在')
     7     def __setattr__(self, key, value):  #限制赋值,无法对属性直接赋值,必须要对__dict__进行操作赋值
     8         print('----> from setattr')
     9         # self.key=value #这就无限递归了,任何赋值操作都会调用__setattr__的运行,所以....
    10         # self.__dict__[key]=value #应该使用这种方式,操作字典可以赋值成功
    11     def __delattr__(self, item):
    12         print('----> from delattr')
    13         # del self.item #无限递归了,同__setattr__方法的无限递归
    14         self.__dict__.pop(item)
    15 #__setattr__添加/修改属性会触发它的执行
    16 f1=Foo(10)
    17 f1.__setattr__('a',1)   #不是直接操作字典,无法赋值
    18 print(f1.__dict__) # 因为重写了__setattr__,凡是赋值操作都会触发它的运行,什么都不写,就是根本没赋值,除非直接操作属性字典,否则永远无法赋值
    19 f1.z=3
    20 print(f1.__dict__)
    21 #__delattr__删除属性的时候会触发
    22 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    23 del f1.a    #删除的时候如果上面函数是del self.item,会无限递归
    24 print(f1.__dict__)
    25 
    26 #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
    27 f1.xxxxxx

    包装(对标准数据类型进行方法修改)

    通过继承和派生的方式,进行修改源生数据类型的方法

     1 class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
     2     def append(self, p_object):
     3         '派生自己的append:加上类型检查'
     4         if not isinstance(p_object,int):
     5             raise TypeError('must be int')
     6         super().append(p_object)
     7     @property
     8     def mid(self):
     9         '新增自己的属性'
    10         index=len(self)//2
    11         return self[index]
  • 相关阅读:
    高版本Visual Studio和低版本ArcGIS共存 工具箱没有控件的解决方法
    Geodesic 什么是“测地线的”?
    向QGIS项目组提交了一份建议
    QGIS 3.4 3.6 另存栅格图层到GeoPackage出现覆盖问题 解决方案
    Dijkstra.NET 库体验报告
    QGIS练手
    GeoPackage
    QGIS练手
    postgresql 修改字段名称
    django signal
  • 原文地址:https://www.cnblogs.com/chenqizhou/p/7200905.html
Copyright © 2020-2023  润新知