• Python面向对象之反射


    一、补充

    @classmethod

    整个方法中没有用到对象命名空间中的名字,且用到了类的命名空间中的名字(普通方法和属性property除外)

    类方法的默认参数:cls 调用这个发方法的类

    类方法的调用方式:通过类名调用

    通过类名调用的本质是方法

     

    @statimethod

    将一个普通函数放到类中来就给这个函数加一个@staticmethod装饰器

    这个函数就不需要传默认的参数:self,cls

    静态方法的调用方式:通过类名调用

    通过类名调用本质是函数

     

    from types import MethodType,FunctionType    配合isinstance使用,判断是方法还是函数

    通过类名调用,@classmethod的是方法,@statimethod的是函数

    from types import FunctionType,MethodType
    class Foo:
        @classmethod
        def func1(cls):pass
    
        @staticmethod
        def  func2():pass
    
    print('Foo.func1-Function:',isinstance(Foo.func1,FunctionType))     # 判断类方法是否函数
    print('Foo.func1-Method:',isinstance(Foo.func1,MethodType))         # 判断类方法是否方法
    print('----------------------------------------')
    print('Foo.func2-Function:',isinstance(Foo.func2,FunctionType))     # 判断静态方法是否函数
    print('Foo.func2-Method:',isinstance(Foo.func2,MethodType))         # 判断静态方法是否方法
    
    '''
    Foo.func1-Function: False
    Foo.func1-Method: True
    ----------------------------------------
    Foo.func2-Function: True
    Foo.func2-Method: False
    '''

     

    通过对象调用,@classmethod的是方法,@statimethod的是函数

    from types import FunctionType,MethodType
    class Foo:
        @classmethod
        def func1(cls):pass
    
        @staticmethod
        def  func2():pass
    
    f = Foo()
    print('Foo.func1-Function:',isinstance(f.func1,FunctionType))     # 判断对象类方法是否函数
    print('Foo.func1-Method:',isinstance(f.func1,MethodType))         # 判断对象类方法是否方法
    print('----------------------------------------')
    print('Foo.func2-Function:',isinstance(f.func2,FunctionType))     # 判断对象静态方法是否函数
    print('Foo.func2-Method:',isinstance(f.func2,MethodType))         # 判断对象静态方法是否方法
    
    '''
    Foo.func1-Function: False
    Foo.func1-Method: True
    ----------------------------------------
    Foo.func2-Function: True
    Foo.func2-Method: False
    '''

     

    类可以被调用,对象不能被调用

    def func(args):
        if callable(args):
            print(args())
        else:
            print('not callable:',args)
    
    class Foo:pass
    
    f = Foo()
    func(Foo)           # 类     <__main__.Foo object at 0x0000016AE645C278>
    func(f)             # 对象    not callable: <__main__.Foo object at 0x0000016AE645C320>

     

    总结:

    需要明确传递参数的是function(函数),不需要明确传递参数的是method(方法)。类直接调用是function(函数),类的实例调用的是method(方法)

    类方法:类调用和对象调用都是method(方法)

    静态方法:类调用和对象调用都是function(函数)

    # 判断函数、方法、对象
    from types import MethodType,FunctionType
    def func(*args):
        function_count = 0
        method_count = 0
        foo_obj = 0
    
        for item in args:
            if isinstance(item,FunctionType):function_count += 1
            elif isinstance(item,MethodType):method_count += 1
            elif isinstance(item,Foo):foo_obj += 1
    
        return {'function_count': function_count, 'method_count': method_count, 'foo_obj': foo_obj}
    
    def func1():pass
    class Foo:
        def method1(self):pass
    
    f1 = Foo()
    ret = func(func1,f1.method1,Foo.method1,Foo(),func,f1)
    print(ret)
    
    '''
    {'function_count': 3, 'method_count': 1, 'foo_obj': 2}
    '''

     

    类、对象内存机制的解析

     

    二、反射

    反射作用:使用字符串数据类型的变量名来获取这个变量的值

    使用反射的三个场景:

    ① input

    ② 文件:从文件中读出的字符串,想转化成变量的名字

    ③ 网络:将网络传输的字符串转化成变量的名字,函数名是变量,类名也是变量,直接执行变量

     

    反射变量的方式:

    ① 反射类中的变量(反射静态变量,类方法,静态方法)

    ② 反射对象中的变量(反射对象中的对象属性,普通方法)

    ③ 反射模块中的变量

    ④ 反射本文件中的变量

     

    反射使用的常用函数:

    ① hasattr() 用于判断对象是否包含对应的属性

    ② getattr() 获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。
    需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,
    可以在后面添加一对括号。

    getattr(变量名:命名空间,字符串:属于一个命名类的变量名)

    ③ setattr() 给对象的属性赋值,若属性不存在,先创建再赋值

    setattr() 接收三个参数,命名空间,‘变量名’,变量值

    ④ delattr() 删除 object对象 中的 name属性

     

    三、反射类中的变量

    ① 反射静态变量

    class A:
        city = 'Shenzhen'
    
    if hasattr(A,'city'):           # 判断类中是否存在该变量名,变量名字符串格式,相当于 A.city in A
        ret = getattr(A,'city')     # getattr(类名,变量名的字符串格式),相当于 ret = A.city
        print(ret)                  # Shenzhen

     

    ② 反射类方法

    class B:
        @classmethod
        def func(cls):              # 类方法
            return 666
    
    if hasattr(B,'func'):           # 判断类中是否存在该变量名,变量名字符串格式,相当于B.func in B
        ret = getattr(B,'func')     # getattr(类名,变量名的字符串格式),相当于 ret = B.func
        print(ret)                  # <bound method B.func of <class '__main__.B'>>
        print(ret())                # 执行B.func()    666

     

    ③ 反射静态方法

    class C:
        @staticmethod
        def func():                 # 静态方法
            return 333
    
    if hasattr(C,'func'):           # 判断类中是否存在该变量名,变量名字符串格式,相当于C.func in C
        ret = getattr(C,'func')     # getattr(类名,变量名的字符串格式),相当于 ret = C.func
        print(ret)                  # <function C.func at 0x000001D058918BF8>
        print(ret())                # 执行C.func()    333

     

    四、反射对象中的变量

    ① 反射对象属性

    class A:
        name = 'gg'
        def __init__(self,city):
            self.city = city            # 对象属性
    
    
    a = A('广州')
    if hasattr(a,'city'):
        ret = getattr(a,'city')         # 相当于 ret = a.city
        print(ret)                      # 广州
        print(a.city)                   # 广州

     

    ② 反射普通方法

    class B:
        def func(self):
            print(666)
    
    b = B()
    if hasattr(b,'func'):
        ret = getattr(b,'func')         # 相当于 ret = b.func
        print(ret)                      # <bound method B.func of <__main__.B object at 0x00000242F27DC5F8>>
        ret()                           # 666
        b.func()                        # 666

     

    五、反射模块中的变量

    import os
    getattr(os,'rename')('a.txt','b.txt')   # 相当于 os.rename('a.txt','b.txt')
    # os.rename('a.txt','b.txt')

     

    六、反射本文件中的变量

    import sys
    city = '北京'
    print(sys.modules['__main__'])          # 本文件的命名空间
    print(sys.modules['__main__'].city)     # 相当与 print(city)
    print(sys.modules[__name__])            # 本文件的命名空间(默认使用此方式)
    # __name__ == '__main__'
    ret = getattr(sys.modules[__name__],'city')   # 相当于 ret = city , 相当于 sys.modules['__main__'].city
    ret = getattr(sys.modules[__name__],'city')   # 相当于本文件中的city变量
    print(ret)

     

    七、setattr() 和 delattr()

    setattr(object, name, value)
    object -- 对象。
    name -- 字符串,对象属性。
    value -- 属性值。

    class A:pass
    
    setattr(A,'city','广州')      # 相当于 A.city = '广州'
    print(A.__dict__)              
    print(A.city)                 # 广州

     

    delattr(object, name)
    object -- 对象。
    name -- 必须是对象的属性。

    class B:
        city = '上海'
    
    delattr(B,'city')               # 相当于 del B.city

     

    八、内置方法

    内置方法:不是需要程序员定义,本身就存在在类中的方法就是内置方法

    内置方法的形式: __名字__

    名字——双下方法,魔术方法,内置方法

     

    __init__ 类的初始化方法,不需要主动调用,而是在类的实例化的时候内部自动调用的

    所有的双下方法,都不需要直接去调用,都是有另一种自动触发它的语法

     

    __str__

    __str__的方法,必须return str类型

    ①当打印一个对象的时候触发__str__,打印的是__方法的返回值

    ②当使用%s格式化的时候,触发__str__

    ③str强转数据类型的时候,触发__str__

    class A:
        def __init__(self,city,province):
            self.city = city
            self.province = province
    
        def __str__(self):
            return '%s在%s内' % (self.city,self.province)
    
    a = A('广州市','广东省')
    print(a)                
    print('%s' % a)
    print(str(a))
    
    '''
    广州市在广东省内
    广州市在广东省内
    广州市在广东省内
    '''

     

    __repr__

    __repr__的方法,必须return str类型

    __repr__相当于__str__的备胎,有__str__的时候执行__str__,没有__str__的时候,执行__repr__

    repr()内置函数对应的结果是__repr__的返回值

    ① 当使用repr()的时候触发__repr__

    ② 当使用%r格式化输出的时候触发__repr__

    ③ 当打印一个对象的时候触发__repr__,打印的是__方法的返回值

    ④ 当使用%s格式化的时候,触发__repr__

    ⑤ str强转数据类型的时候,触发__repr__

    class A:
        def __init__(self,city,province):
            self.city = city
            self.province = province
    
        def __repr__(self):
            return '%s在%s内' % (self.city,self.province)
    
    a = A('深圳市','广东省')
    print(a)
    print('%s' % a)
    print(str(a))
    print(repr(a))
    print('%r' % a)
    
    '''
    深圳市在广东省内
    深圳市在广东省内
    深圳市在广东省内
    深圳市在广东省内
    深圳市在广东省内
    '''

     

    继承关系中,__str__和__repr__的优先级:

    结论:子类的__str__ >>> 父类的__str__ >>> 子类的__repr__ >>> 父类的__repr__

  • 相关阅读:
    开发生产测试环境中的Swagger
    Linux ssh命令详解【转】
    mysql元数据库
    Spring Boot中使用Swagger2构建强大的RESTful API文档【转】
    docker【转】
    作为Java开发之新工作环境配置简明攻略
    CBA经典文章【转】
    Java中的日志【转】
    spring框架学习(六)AOP
    spring框架学习(五)注解
  • 原文地址:https://www.cnblogs.com/st-st/p/9567113.html
Copyright © 2020-2023  润新知