一、isinstance 和 issubclass
1、isinstance(obj,cls)检查是否obj是否是类 cls 的对象。
2、issubclass(sub, super)检查sub类是否是 super 类的派生类
  判断结果为布尔值:是返回True,不是返回False

 

 1 class Bar:  #定义父类
 2     pass
 3 class Foo(Bar):  #定义子类 继承 Bar
 4     pass
 5 
 6 class A:  #定义类 A
 7     pass
 8 
 9 obj=Foo() #实例化
10 a = A()   #实例化
11 #isinstance
12 print(isinstance(obj,Foo))  #查看obj是否是类Foo的对象
13 print(isinstance(obj,Bar))  #查看obj是否是类Bar的对象
14 print(isinstance(a,A))      #查看a是否是类A的对象
15 print(isinstance(a,Foo))    #查看a是否是类Foo的对象
16 #issubclass
17 print(Foo.__bases__)     #之前查看继承的方式
18 print(issubclass(Foo,Bar))  #查看类Foo 是否是类Bar的子类
19 print(issubclass(A,Bar))    #查看类A 是否是类Bar的子类
20 
21 #执行结果:
22 True
23 True
24 True
25 False
26 (<class '__main__.Bar'>,)
27 True
28 False

 

 

二、反射:getattr,setattr,delattr,hasattr
  1、定义:

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

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

2、应用:

  1) hasattr   查找
  hasattr(object,'name') 应用于类或对象,查看有没有所对应的方法。实质还是从类或对象的名称空间去查找。判断结果返回布尔值,有为True,没有为False.

  2)getattr   获取  

  getattr(object,name,‘返回值’) 通过字符串获取 查看有没有这个属性,获取绑定方法。

  实质还是从类或对象的名称空间去查找,有的话返回为函数内存地址,加()就能运行。

  3)setattr 设置
  setattr(x,y,v)   x=类或对象, y='字符串类型的属性名',v=value 值  实质是给类或是对象添加数据属性。

  4)delattr 删除
  delattr(x,y)   x = 类或对象,y = '字符串类型的属性名'   删除类或是对象内的某个属性!

#coding = utf-8
#通过字符串的形式,为类或是对象添加属性
class People:  #定义一个类
    country = 'China'
    def __init__(self,name):
        self.name = name

    def test(self):
        print('test')

p = People('zh')  #实例化

#hasattr
h = hasattr(p,'name')  #查看对象p有没有name属性
print(h)  #打印布尔值

#执行结果:
True

#getattr(object,name,default=None(or'自定义的值'))
print(p.__dict__)       #查看对象的名称空间
print(People.__dict__)  #查看类的名称空间
g = getattr(p,'name')   #获取对象name方法
g1 = getattr(p,'test')  #获取对象test的绑定方法
g2 = getattr(People,'test')  #获取类test方法
g3 = getattr(People,'work',"没有此方法!")  #获取类work方法,没有打印value值
print(g,g1,g2,g3)  #打印
g1()  #执行对象对应的方法,不需要传值
g2(p)  #执行类对应的方法,需要传值

#执行结果:
{'name': 'zh'}
{'__module__': '__main__', 'country': 'China', '__init__': <function People.__init__ at 0x00000000028EC9D8>, 'test': <function People.test at 0x00000000028ECA60>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
zh <bound method People.test of <__main__.People object at 0x00000000028FF208>> <function People.test at 0x00000000028ECA60> 没有此方法!
test
test

#setattr()只能更改类或是对象内的 数据属性,函数属性没法变更。
print(p.__dict__)   #设置前查看对象的名称空间
setattr(p,'sex','male') #设置sex属性
setattr(p,'age',18)     #设置age属性
print(p.__dict__)      #设置后查看对象的名称空间
print(p.sex,p.age)   #打印

#执行结果:
{'name': 'zh'}
{'name': 'zh', 'sex': 'male', 'age': 18}
male 18

#delattr
print(p.__dict__) #删除前查看对象的名称空间
delattr(p,'age')  #删除 对象 的数据属性
print(p.__dict__)  #删除操作完成,在对象的名称空间查看

#执行结果:
{'name': 'zh', 'sex': 'male', 'age': 18}
{'name': 'zh', 'sex': 'male'}

  5)反射当前位置的模块成员。

  此处先明确两个概念:

    脚本文件:将程序写到一个文件中,以***.py的方式保存,使用的时候 利用python ***.py进行执行,该文件就称为脚本文件。

    模块:import 模块名 导入的文件就是模块,文件名就是模块名。

    在当前位置获取当前文件中定义的函数,如果直接将本文件以模块的形式导入文件中,程序执行直接触发递归,无法实现功能,此时在自己位置就不能导入自己的模块。此时就需要把本文件转成一个脚本模块,既可以导入到别的模块或文件中用,另外该模块自己也可执行。所以就需要使用下面的方法:
方法:import sys  #导入sys模块

this_modules = sys.modules[__name__](有返回值)  获取一个模块,将当前位置的文件转成一个脚本模块(有具体的文件地址)

print(__name__)

注意:__name__的用法:  如果我们是直接在本文件执行,那该文件中'__name__' == '__main__',但是如果从另外一个.py文件通过import导入该文件的时候,这时__name__的值就是我们这个py文件的名字而不是__main__。(有一种加上保护锁的感觉)

 

import sys  #导入sys模块
def add():
    print('add')

def change():
    print('change')

def search():
    print('search')

def delete():
    print('delete')

this_module = sys.modules[__name__]   #利用sys模块中的modules方法,将本文件转成脚本模块
print(this_module)  #查看
print(__name__)  #查看__name__
while True:
    m = input('input something:').strip()
    if not m :continue
    if hasattr(this_module,m):  #判断输入的内容在不在模块 类中
        func = getattr(this_module,m)  #获取这个方法,拿到返回值
        func()  #执行函数
    else:
        print('没有此方法!')

#执行结果:
<module '__main__' from 'F:/py_fullstack_s4/day31/__name__及反射的用途.py'>
__main__
input something:add
add
input something:work
没有此方法!

 

3、反射的好处:

  好处一:可以利用反射实现可插拔机制。

  可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,即事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。不影响其他人员对程序的调用和开发。

class FtpClient:
    'ftp客户端,但是还没有实现具体的功能'
    def __init__(self,addr):
        print('正在连接服务器[%s]' %addr)
        self.addr=addr
    def get(self):
        print('get------->')
ftpclient.py

相关文章:

  • 2022-01-27
  • 2021-08-23
  • 2021-05-20
  • 2021-11-28
  • 2021-12-07
  • 2021-07-25
  • 2021-09-21
  • 2021-09-08
猜你喜欢
  • 2021-09-06
  • 2021-09-22
  • 2021-09-22
  • 2022-01-24
  • 2022-02-01
  • 2021-09-22
  • 2021-10-25
相关资源
相似解决方案