zoukankan      html  css  js  c++  java
  • isinstance、issubclass以及反射


    isinstance(object,class)

    判断对象object是否为class的实例或者是class直接、间接或虚拟子类,是则返回True。如果 object 不是给定类型的对象,函数将总是返回 False。isinstance与type类似,但type只能判断对象所属的类,不能判断基类。

    >>> x = 10
    >>> isinstance(x,int)
    True
    >>> isinstance(x,object)
    True
    >>> isinstance(x,str)
    False
    
    >>> class Myint(int):
    ...     pass
    ...
    >>> isinstance(Myint,object)
    True
    >>> isinstance(Myint,int)  # 不是给定类型的对象
    False
    

    如果 classinfo 是类型对象元组(或由其他此类元组递归组成的元组),那么如果 object 是其中任何一个类型的实例就返回 True

    >>> isinstance(x,(int,str))
    True
    >>> isinstance(x,((int,str),list))
    True
    >>> isinstance(x,((dict,str),list))
    False
    

    如果 classinfo 既不是类型,也不是类型元组或类型元组的元组,则将引发 TypeError 异常。

    >>> isinstance(x,x)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: isinstance() arg 2 must be a type or tuple of types
    

    issubclass(class,classinfo)

    如果 classclassinfo 的 (直接、间接或 虚拟) 子类则返回 True。 类会被视作其自身的子类。 classinfo 也以是类对象的元组,在此情况下 classinfo 中的每个条目都将被检查。 在任何其他情况下,都将引发 TypeError 异常。

    class A:
        pass
    
    class B(A):
        pass
    
    class C(B):
        pass
    
    x = C()
    
    print(issubclass(C,A))  # True
    print(issubclass(x,A))  # TypeError: issubclass() arg 1 must be a class
    

    反射

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

    内置有四个函数:

    hasattr(obj,str)

    判断一个对象是否有某个属性或方法。

    class Coder:
        head = 1
        def work(self):
            print('打工技能')
    
    f1 = 'head'
    f2 = 'tail'
    # 判断类中是否有此属性
    print(hasattr(Coder,f1))  # True
    print(hasattr(Coder,f2))  # Fasle
    
    # 判断对象中是否有此属性.
    c1 = Coder()
    c1.tail = '哈哈哈'
    print(hasattr(c1,f2))  # True
    

    通过判断一个字符串是否在__dict__字典中,也能判断该对象是否有该属性或方法。

    class Coder:
        head = 1
        def work(self):
            print('打工技能')
    
    print('head' in Coder.__dict__)
    
    True
    

    getattr(obj,str, [None])

    通过字符串获取对象中的属性或方法,可以指定属性不存在时返回None或其他值。

    class Coder:
        head = 1
        def work(self):
            print('打工技能')
    
    
    d = getattr(Coder,'work')
    print(d)  # 函数内存地址 <function Coder.work at 0x00000000033BD430>
    
    # 等同于下面,通过点获取,正常的调用方式,区别在于getattr可以用字符串。
    f = Coder.work
    
    d(1)  # 此时d就是work方法,加括号调用,但要给self传个参数。
    打工技能
    
    d2 = getattr(Coder,'tail')  # 没有给定属性则报错,所以可以先用hasattr判断一下。
    AttributeError: type object 'Coder' has no attribute 'tail'
    
    class A:
        pass
    
    print(getattr(A,'x','abc'))  # 没有该属性则返回指定的值。
    
    abc
    

    setattr(obj,str_name,str_value)

    1、通过字符串给对象赋值数据属性。

    class Coder:
        head = 1
        def work(self):
            print('打工技能')
    
    setattr(Coder, 'tail', 0)
    print(Coder.tail)  
    0
    
    c1 = Coder()
    setattr(c1,'name','张三')
    print(c1.name)
    张三
    

    2、通过字符串给类赋值函数方法。

    class Coder:
        head = 1
        def work(self):
            print('打工技能')
    
    def run(self):
        print('跑步技能')
    
    c1 = Coder()
    setattr(Coder,'run',run)  # 给类赋值
    c1.run()  # 调用对象的绑定方法会将对象传进去。
    
    setattr(c1,'run',run)  # 给对象赋值,那么仅为普通函数,不会自动将对象传进去,需要手动出入。
    c1.run(c1) 
    

    delattr(obj,str)

    通过字符串删除对象的属性或方法。

    class Coder:
        head = 1
        def work(self):
            print('打工技能')
    
    delattr(Coder,'work')
    print(Coder.work) 
    AttributeError: type object 'Coder' has no attribute 'work'
    

    反射隐藏属性

    hasattr:

    class Coder:
        __head = 1
        
        def __work(self):
            print('打工技能')
    
    print(hasattr(Coder, '_Coder__head'))
    True
    

    getattr:

    class Coder:
        __head = 1
        def __work(self):
            print('打工技能')
    
    h = getattr(Coder,'_Coder__work')
    h(None) 
    打工技能
    

    setattr:

    class Coder:
        head = 1
        def work(self):
            print('打工技能')
    
    def run():
        print('跑步技能')
    
    setattr(Coder,'_Coder__run',run)
    Coder._Coder__run()  # 调用时同样需要变形。
    跑步技能
    

    反射模块

    使用hasattr判断模块是否有某个成员。

    import time
    print(hasattr(time,'time'))
    True
    

    getattr获取方法。

    my_time = getattr(time,'time')
    print(my_time())
    1609226695.2641723
    

    __import__('字符串'):会导入给定字符串的模块。

    ti = __import__('time')
    print(ti.time())
    1609155137.1639736
    

    输入路径导入:

    # d目录内的test模块内容
    def a():
        print('这是aaaaaaa')
    
    module_path = input('输入导入的模块: ').strip()
    module = __import__(module_path, fromlist=True )  # 需要加个参数
    module.a()
    

    会将字符串当成模块名,所以不要加from和import。

    输入导入的模块: d.test
    这是aaaaaaa
    

    Python中更推荐使用的反射模块方式是使用importlib模块。

    import importlib
    
    m = importlib.import_module('d.test')
    m.a()
    
    这是aaaaaaa
    

    不用加fromlist参数,模块名和模块路径都能接收,程序健壮性更高。


    反射的应用

    应用一:实现可插拔机制。

    例如,多肉和张三协同开发一个项目,张三在写程序的时候需要用到多肉所写的类,但多肉旅游去了,还没有完成他的类,张三想到了反射,使用反射机制张三可以继续完成他的代码,等多肉旅游回来后在继续完成类的定义,并实现张三想要的功能。

    也就是说,可以事先定好接口,接口只有在被完成后才会真正执行,这实现了即插即用,其实是一种 “ 后期绑定 ” ,可以事先将主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。

    # 多肉还没有实现的功能。
    class FtpClient:
        '''ftp客户端,但还未实现具体的功能'''
        def __init__(self,ip):
            print('正在连接服务器{}'.format(ip))
    		self.ip = ip
    
    # 张三代码可正常编写
    
    from module import FtpClient
    
    f1 = FtpClient(192.168.10.10)
    if hasattr(f1, 'get'):  # 判断get方法是否存在。
        func_get = getattr(f1, 'get')  
        func_get()
    else:
        print('方法不存在')
    

    应用二:

    能在程序的运行过程中,接收用户的输入,以此来执行指定的功能,从而达到一个动态修改、执行属性或方法的作用。

    class Ftp:
        def __init__(self, ip, port):
            self.ip = ip
            self.port = port
            
        def get(self):
            print('get功能')
                
        def put(self):
            print('put功能')
            
        def run(self):
            while 1:
                choice = input('>>>(q退出):').strip()
                
                if choice.lower() == 'q':
                    print('退出')
                    break
    
            	if hasattr(self, choice):
                    method = getattr(self, choice)
                    method()
                else:
                    print('输入的指令不存在。')
                    
    ftp = Ftp("192.168.10.10/24", 80)
    ftp.run()
    

    执行:

    >>>(q退出):get
    get功能
    >>>(q退出):put
    put功能
    >>>(q退出):aaa
    输入的指令不存在。
    >>>(q退出):q
    退出
    

  • 相关阅读:
    mysql 性能优化方案
    MYSQL 优化常用方法
    MongoDB集群架构及搭建
    memcache分布式 [一致性hash算法] 的php实现
    memcache 的内存管理介绍和 php实现memcache一致性哈希分布式算法
    【转】linux 查看进程启动路径
    centos7 编译安装nginx+tcp+grpc转发
    mongodb笔记
    【转】mysql 解事务锁
    【转】centos7 搭建etcd集群
  • 原文地址:https://www.cnblogs.com/ChiRou/p/14207033.html
Copyright © 2011-2022 走看看