反射

反射

一:isinstance, type, issubclass

1. issubclass(),这个内置函数可以判断xxx类是否是yyy类的型的子类。
例:
    class Base:
        pass
    class Foo(Base):
        pass
    class Bar(Foo):
        pass
        
    print(issubclass(Bar,Foo))  # True
    print(issubclass(Foo,Bar))  # False
    print(issubclass(Bar,Base)) # True
    
    
     
    

2. 前面学习过type(),查看obj是由哪个类创建的。
例:
    class Foo:
        pass

    obj = Foo()
    print(obj,type(obj))  # 查看obj的类
     # <__main__.Foo object at 0x00000000024B8160> <class '__main__.Foo'>
    

2.1 现在type()可以判断xxx是否是xxx数据类型的。
例:
    class Boy:
        pass
    class Girl:
        pass

    # 统计传进来的男生和女生分别有多少
    def func(*args):
        b = 0
        g = 0
        for obj in args:
            if type(obj) == Boy:
                b += 1
            elif type(obj) == Girl:
                g += 1
        return b, g
    ret = func(Boy(),Girl(),Boy(),Girl(),Boy(),Girl(),Boy(),Girl())
    print(ret)
     # (4,4)

2.2 也可以先判断好数据类型必须是int或者float,进行有意义的计算。
例:
    def add(a,b):
    if (type(a) == int or type(a) == float) and (type(b) == int or type(b) == float):
        return a + b
    else:
        print('报错')    
    

3. isinstance 也可以判断xxx是否是yyy类型的数据,但是isinstance没有typename精准。
例:
    class Base:
        pass
    class Foo(Base):
        pass
    class Bar(Foo):
        pass

    print(isinstance(Foo(),Foo))   # True
    print(isinstance(Foo(),Base))  # True
    print(isinstance(Foo(),Bar))   # False
     
注:isinstance可以判断该对象是否是xxx家族体系的(只能往上判断,不能往下判断)

二:区分函数和方法

如何区分函数和方法
例:
    def func():
        pass
        print(func)   # <function func at 0x0000000002071E18>
            
    
    class Foo:
        def chi(self):
            print('1')
    
    f = Foo()
    print(f.chi)   # <bound method Foo.chi of <__main__.Foo object at 0x00000000024E83C8>>
    
函数下打印的时候,显示的是function;方法在打印的时候现实的method.
但其实不一定是这样的。
例:
    class Foo:
        def chi(self):
            print('我是吃')

    @staticmethod
    def ststic_method():
        pass

    @classmethod
    def class_method(cls):
        pass

    f = Foo()
    print(f.chi)   # <bound method Foo.chi of <__main__.Foo object at 0x00000000024C83C8>>
    print(f.ststic_method)    # <function Foo.ststic_method at 0x00000000022F7950>
    print(f.class_method)     # <bound method Foo.class_method of <class '__main__.Foo'>>
    
    print(Foo.chi) # <function Foo.chi at 0x00000000024F78C8>
    print(Foo.ststic_method)  # <function Foo.ststic_method at 0x00000000024B7950>
    print(Foo.class_method)   # <bound method Foo.class_method of <class '__main__.Foo'>>
    
     注: function 表示是函数
         method 表示是方法

结论:
    1.类方法,不论任何情况都是方法。
    2.静态方法,不论任何情况都是函数。
    3.实例方法,如果是实例(对象)访问就是方法,类名访问就
    
    是函数。
    
    
如何用程序分辨方法和函数,借助于types模块。
例:
    # 所有的方法都是MethodType的实例
    #所有的函数都是FunctionType的实例

    from types import MethodType ,FunctionType        
    def func():
        pass

    # print(isinstance(func,FunctionType))   # True
    # print(isinstance(func,MethodType))     # False


    class Foo:
        def chi(self):
            print('我是吃')

    @staticmethod
    def static_method():
        pass

    @classmethod
    def class_method(cls):
        pass

    obj = Foo()
    print(type(obj.chi))   # <class 'method'>
    print(type(Foo.chi))   # <class 'function'>
    print(isinstance(obj.chi,MethodType))   # True
    print(isinstance(Foo.chi,FunctionType)) # True
    
    print(isinstance(Foo.static_method,FunctionType))   # False
    print(isinstance(Foo.static_method,MethodType))     # True
    
    print(isinstance(Foo.class_method,MethodType))   # True
    print(isinstance(Foo.class_method,FunctionType)) #  False
        
注:用types中的FunctionType和MethofType可以区分当前内容是方法还是函数。

三:反射

例:
    我们需要用别人写的代码,但是我们并不清楚代码中的功能,这时就需要我们自己去测试,来拿到自己想用的功能。
    
    首先拿到 代码:某人.py
    def chi():
        print('某人能吃一头牛')
    def he():
        print('某人能喝一条河')
    def chui():
        print('某人能八天吹破')
    def shui():
        print('某人能睡一年')

    # 现在需要自己一个一个的调用,在调用之前已经知道代码中的功能。

    import moster

    while 1:
        print('''代码中功能有
            chi
            he
            chui
            shui
        大概其就这么多   
        ''')
        gn = input('请输入你想测试的功能:')
        if gn == 'chi':
            master.chi()
        elif gn == 'he':
            master.he()
        elif gn == 'chui':
            master.chui()
        elif gn == 'shui':
            master.shui()
        else:
            print('一共四个功能')


现在某人.py文件里有100个功能,我们需要进行100次测试,工程有点浩大。但是我们可以使用反射来简单的完成这个好大的工程,
如果能通过字符串动态来访问模块中的功能,就能解决这个问题。
根据上面的操作来进行逆向操作,我们先输入自己想要的功能,然后去代码模块里找,这就叫:反射
例:
    import moster
    while 1:
        print('''代码中功能有
            chi
            he
            chui
            shui
        大概其就这么多   
        ''')
        gn = input('请输入你想测试的功能:')
        func = getattr(moster,gn)
        func()
    
    
getattr(对象.字符串): 从对象里获取到xxx功能,此时xxx是一个字符串,get表示找,attr表示属性(功能)。
但是如果在代码里找不到我想要的内容,就会报错,所以在获取attr之前先判断一下,代码里有没有attr。
例:
   import master
    from types import FunctionType

    while 1:
        print('''代码中功能有
            chi
            he
            chui
            shui
        大概其就这么多   
        ''')
        gn = input('请输入你想测试的功能:')
        if hasattr(master,gn):  # 如果master里有你功能,获取这个功能并执行。
            attr = getattr(master,gn)   # 判断是否是函数,只有函数才可以被调用
            if isinstance(attr,FunctionType):
                attr()
            else:
                print(attr)
 
 
这里讲到两个函数,一个是getattr(),一个是hasattr()。getattr()用来获取信息,hasattr()用来判断xxx中否包含了xxx功能。
例:
     class Preson:
        country = '大清'
        def chi(self):
            pass
            
    # 类中的内容可以这样动态地进行获取
    print(getattr(Preson,'country'))
    print(getattr(Preson,'chi'))   # 相当于 类名.'静态属性'  函数


    # 对象一样可以
    obj = Preson()
    print(getattr(obj,'country'))
    print(getattr(obj,'chi'))     # 相当于 对象.'方法名'  方法       

总结:
    getattr可以从模块中获取内容,也可以从类中获取内容,也可以从对象中获取内容。
    在python中一切皆为对象,那就可以认为getattr从对象中动态的获取成员。


补充:
反射一共有4个函数:
    1:getattr(obj.str) 从obj中获取str成员
    2: hasattr(obj.str) 判断obj中是否包含str成员
    3: setattr(obj,str,value) 把obj中的成员设置成value,注:这里的value可以是值,也可以是函数或者方法。
    4:delattr(obj,str) 把obj中的str成员删除

注:以上操作都是在内存中进行,不会影响源代码。

class Foo:
    pass

f = Foo()
print(hasattr(f,'chi'))  #  False

setattr(f,'chi','123')
print(f.chi)     # 添加了一个属性信息

setattr(f,'chi',lambda x : x + 1)
print(f.chi(3))   # 4
print(f.chi)  # 此时chi既不是静态方法,也不是实例方法,也不是类方法,而是相当于在类中写了一个self.chi = lambda
print(f.__dict__)  # {'chi': <function <lambda> at 0x0000000002081E18>}

delattr(f,'chi')   #  删除 chi
print(hasattr(f,'chi'))  #  判断f中是否还包含'chi'   结果:False
posted @ 2018-10-22 21:06  過去  阅读(141)  评论(0编辑  收藏  举报