zoukankan      html  css  js  c++  java
  • issubclass/type/isinstance、函数和方法、反射、callable、特殊成员补充

    一、issubclass/type/isinstance(***)

      1、issubclass(参数1, 参数2):检查第一个参数是否是第二个参数的 子子孙孙类,如下示例:

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

      2、type():获取当前对象时由哪个类创建,如下示例:

        # #####示例一:判断一个参数是不是某一个指定类的对象
        class Foo(object):
            pass
    
        obj = Foo()
        print(obj,type(obj)) 
        # <__main__.Foo object at 0x0000000002618F60> <class '__main__.Foo'>
        if type(obj) == Foo: # 判断一个参数是不是某一个指定类的对象
            print('obj是Foo类型')
    
        # #####示例二:练习题:判断函数的参数分别是哪个类的对象
        class Foo(object):
            pass
    
        class Bar(object):
            pass
    
        def func(*args):
            foo_counter = 0
            bar_counter = 0
            for item in args:
                if type(item) == Foo:
                    foo_counter += 1
                elif type(item) == Bar:
                    bar_counter += 1
            return foo_counter, bar_counter
    
        print(func(Foo(), Bar(), Foo()))  # (2, 1)
        # 补充:示例三:如何判断参数是不是一个类
        class Foo(object):
            pass
        obj = Foo()
        print(type(Foo) == type) # True
        print(type(obj) == type) # False

      3、isinstance(参数1, 参数2):检查第一个参数是否是第二个参数的实例,如下示例:

        # #####示例一:判断一个参数是不是某一个指定类或其父类的对象
        class Base:
            pass
        class Foo(Base):
            pass
        class Bar(Foo):
            pass
        obj1 = Bar()
        print(isinstance(obj1, Bar))  # True
        print(isinstance(obj1, Foo))  # True
        print(isinstance(obj1, Base))  # True
    
        obj2 = Foo()
        print(isinstance(obj2, Bar))  # False

    二、用科学的方式判断是函数和方法(*)

      一般我们笼统的称定义在类中的函数为方法,定义在类外的就是函数,其实是不太严谨的,如下示例:

        # #####示例一:如何看得出是函数还是方法
        def func():
            pass
        class Foo(object):
            def inner(self):
                pass
            @staticmethod
            def detail():
                pass
        print(func)  # <function func at 0x00000000028C99D8>  是函数
    
        obj = Foo()
        print(obj.inner)  # 是方法
        # <bound method Foo.inner of <__main__.Foo object at     0x00000000028D1208>> 
        print(Foo.detail)  # <function Foo.detail at     0x00000000028F9AE8>  是函数
        print(obj.detail)  # <function Foo.detail at 0x00000000028F9AE8>  是函数
    如何看得出是函数还是方法

      其实,在python中,一切皆对象,只要是对象,它就有对应的类,函数是FunctionType创建的,方法是由MethodType创建的,所以,我们可以按照如下示例判断是函数还是方法:

        # #####示例二
        from types import MethodType,FunctionType
        def check(arg):
            """
            检查arg是方法还是函数?
            """
            if isinstance(arg,MethodType):
                print('arg是一个方法')
            elif isinstance(arg,FunctionType):
                print('arg是一个函数')
            else:
                print('不知道是什么')
        check(func)  # arg是一个函数
        check(obj.inner)  # arg是一个方法
        # #####示例三:是不是方法跟写在哪里没关系,跟调用有关系
        class Foo(object):
            def f1(self):
                pass
    
        obj = Foo()
        obj.f1()    # 把f1当做方法,python自动传self值
        print(obj.f1)
        # <bound method Foo.f1 of <__main__.Foo object at 0x0000000002724390>>
        obj = Foo()
        Foo.f1(obj) # 把f1当做函数,需要自己传参数
        print(Foo.f1)  # <function Foo.f1 at 0x0000000002791AE8>
    是不是方法跟写在哪里没有关系,跟调用有关系
        # #####示例四:练习题
        class Foo(object):
            def f1(self):
                pass
            def f2(self):
                pass
            def f3(self):
                pass
            list_display = [f1,f2]
            def __init__(self):
                pass
        for item in Foo.list_display:
            print(item)
            item(123)  # item是函数,所以要自己传参数
        # 结果为:
        # <function Foo.f1 at 0x00000000029A3B70>
        # <function Foo.f2 at 0x00000000029A3BF8>
    练习题一
        # #####示例五
        class Foo(object):
            def f1(self):
                pass
            def f2(self):
                pass
            def f3(self):
                pass
            list_display = [f1,f2]
    
        obj = Foo()
        Foo.list_display.append(obj.f3)
    
        for item in Foo.list_display:
            print(item)
        # 结果为:
        # <function Foo.f1 at 0x0000000002973D90>
        # <function Foo.f2 at 0x0000000002973E18>
        # <bound method Foo.f3 of <__main__.Foo object at 0x0000000002908A90>>
    练习题二

      总结:执行那个类里边的  .什么功能  的时候,如果是 对象.功能,那么这个功能就是方法。

        对象.xxx  --- >  xxx就是方法

        类.xxx    --- >  xxx就是函数

    三、反射(*****)

      重点:v = getattr(obj , “func”)  # 根据字符串为参数(第二个参数),去对象(第一个参数)中寻找与之同名的成员。

    应用一、首先定义一个handler模块,handler.py文件内容如下:

        f0 = 9
        def f1():
            print('F1')
        def f2():
            print('F2')
        def f3():
            print('F3')
        def f4():
            print('F4')
        def f5():
            print('F5')
    handler.py

      现有个需求,用户输入模块中的函数名,则执行该函数,你可能会按照如下方式写代码:

        """
        import handler
        val = input("请输入要执行的函数:")
        if val == 'f1':
            handler.f1()
        elif val == 'f2':
            handler.f2()
        elif val == 'f3':
            handler.f3()
        elif val == 'f4':
            handler.f4()
        elif val == 'f5':
            handler.f5()
        """
    以前的写法

      学习了反射,我们可以这样写,如下示例:

        from types import FunctionType
        import handler
        while True:
            print("""
            系统支持的函数有:
                1. f1
                2. f2
                3. f3
                4. f4
                5. f5
            """)
            val = input("请输入要执行的函数:")  
    
            if hasattr(handler, val):  # 假如  val = "f1"
                func_or_val = getattr(handler, val)  
                # 根据字符串为参数,去模块中寻找与之同名的成员。
                if isinstance(func_or_val, FunctionType):
                    func_or_val()  # 是函数则执行
                else:
                    print(func_or_val)  # 不是函数则打印出来
            else:
                print('handler中不存在输入的属性名')
        

    应用二、用户登录、注销、注册程序:

        class Account(object):
            func_list = ['login', 'logout', 'register']
            def login(self):
                """
                登录
                """
                print('登录111')
            def logout(self):
                """
                注销
                """
                print('注销111')
            def register(self):
                """
                注册
                """
                print('注册111')
            def run(self):
                """
                主代码
                """
                print("""
                    请输入要执行的功能:
                        1. 登录
                        2. 注销
                        3. 注册
                """)
                choice = int(input('请输入要执行的序号:'))
                func_name = Account.func_list[choice-1]
    
                func = getattr(self, func_name)  # self.login
                func()
    
        obj1 = Account()
        obj1.run()

    反射补充:还是以引入handler模块为例:

        import handler
        # hasattr
        v1 = hasattr(handler,'f0')
        v2 = hasattr(handler,'f1')
        v3 = hasattr(handler,'f2')
        v4 = hasattr(handler,'xxx')
        print(v1,v2,v3,v4)  # True True True False
    
        # setattr
        setattr(handler,'x2',999)
        v5 = getattr(handler,'x2')
        print(v5)  # 999
    
        setattr(handler,'f8',lambda x:x+1)
        v6 = getattr(handler,'f8')
        v7 = v6(1)
        print(v7)  # 2
    
        # delattr
        delattr(handler,'f0')
        # v8 = getattr(handler,'f0')
        # print(v8) # AttributeError: module 'handler' has no attribute 'f0'

    总结:

      getattr   # 根据字符串的形式,去对象中找成员;

      hasattr   # 根据字符串的形式,去判断对象中是否有成员;

      setattr   # 根据字符串的形式,动态的设置一个成员(内存);

      delattr   # 根据字符串的形式,动态的删除一个成员(内存);

    四、补充知识点(callable)

      你见过的什么后面可以加括号?

        -  类()             -  对象()

        -  函数()           -  方法()

      以上所有都可以被调用。如何验证呢?如下示例:

        def func():
            pass
    
        class Foo(object):
            def __call__(self, *args, **kwargs):
                pass
            def func(self):
                pass
        obj = Foo()
        print(callable(func))  # True
        print(callable(Foo))  # True
        print(callable(obj))  # True
        print(callable(obj.func))  # True

    五、特殊成员补充

        # print(对象),会自动执行__str__方法
        class Foo(object):
            def __init__(self):
                pass
            def func(self):
                pass
            def __str__(self):
                return "F1"  # 必须返回字符串
        obj = Foo()
        print(obj,type(obj))  # F1 <class '__main__.Foo'>
    __str__
        # __doc__
        class Foo(object):
            """
            这里是注释
            """
            def __init__(self):
                pass
            def func(self):
                pass
            def __str__(self):
                return "F1"
    
        obj = Foo()
        print(obj.__doc__) # 这里是注释
    __doc__
        # __dict__
        class Foo(object):
            def __init__(self, name, age):
                self.name = name
                self.age = age
            def func(self):
                pass
        obj1 = Foo('刘博文', 99)
        obj2 = Foo('史雷', 89)
        print(obj1.__dict__)  # {'name': '刘博文', 'age': 99}
        print(obj2.__dict__)  # {'name': '史雷', 'age': 89}
    __dict__
        # __iter__
        class Foo(object):
            def __init__(self,name,age):
                self.name = name
                self.age = age
            def __iter__(self):
                return iter([11,22,33])
                # 生成器
                # yield 11
                # yield 22
                # yield 33
        """
        如果想要把不可迭代对象 -> 可迭代对象
        1. 在类中定义__iter__方法
        2. iter内部返回一个迭代器(生成器也是一种特殊迭代器)
        """
        obj1 = Foo('刘博文',99)
        for item in obj1:
            print(item)
        # 结果为:
        # 11
        # 22
        # 33
    __iter__
  • 相关阅读:
    http和socket之长连接和短连接区别【转】
    Linux下内存泄漏工具【转】
    arm交叉编译器gnueabi、none-eabi、arm-eabi、gnueabihf等的区别【转】
    C语言字节对齐 __align(),__attribute((aligned (n))),#pragma pack(n)【转】
    简单解读linux的/proc下的statm、maps、memmap 内存信息文件分析【转】
    linux调试工具glibc的演示分析-core dump double free【转】
    Linux信号(signal)机制【转】
    细说JavaScript对象(4): for in 循环
    细说JavaScript对象(3):hasOwnProperty
    细说JavaScript对象(2):原型对象
  • 原文地址:https://www.cnblogs.com/li-li/p/9559686.html
Copyright © 2011-2022 走看看