反射 动态导入 元类

Posted lddragon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射 动态导入 元类相关的知识,希望对你有一定的参考价值。

isinstance(obj cls) 检查obj是否是cls的对象

issubclass(sub, super) 检测sub是否是super的派生类/子类

class Foo(object):    
    pass
obj = Foo()
print(isinstance(obj, Foo)) # True

class Fo(Foo):
    pass
print(issubclass(Fo, Foo))   #True

反射 reflect

python中 反射是指 通过字符串的形式来操作对象的相关属性

getattr(obj, name, default=None) 查找obj中有没有一个name的属性 有的话返回name对应的值 没有的话返回default 默认返回None

hasattr(obj, name)判断obj中有没有一个name的属性 setattr(x, y, z) 给obj中添加 或者修改属性值 有的话覆盖 没有的话修改

delattr(x, y) 给obj中x的属性值删除

class A:
    def __init__(self,name, age):
        self.name = name
        self.age =age

a = A('long', 18)
print(hasattr(a, 'name'))
print(getattr(a, 'name1', '啥都没有你找啥'))
print(getattr(a, 'name', '啥都没有你找啥'))
# print(getattr(a, 'name1'))  #不存在,则报错
print(setattr(a, 'name', 'jaon'))
print(setattr(a, 'name1', 'jaon'))
delattr(a, 'name')  #不存在,则报错

# 类也是对象 也可以使用 改的是共有属性
"""
使用场景:  
反射其实就是对属性的增删改查,但是如果直接使用内置的__dict__来操作,语法繁琐,不好理解

框架设计方式:         
反射被称为框架的基石,为什
因为框架的设计者,不可能提前知道你的对象到底是怎么设计的        
所以你提供给框架的对象 必须通过判断验证之后才能正常使用        
判断验证就是反射要做的事情,        
其实这些方法也就是对__dict__的操作进行了封装 
""""
import importlib
import settings

# 框架已经实现的部分
def run(plugin):
    while True:
        cmd = input("请输入指令:")
        if cmd == "exit":
            break
        # 因为无法确定框架使用者是否传入正确的对象所以需要使用反射来检测
        # 判断对象是否具备处理这个指令的方法
        if hasattr(plugin,cmd):
            # 取出对应方法方法
            func = getattr(plugin,cmd)
            func() # 执行方法处理指令
        else:
            print("该指令不受支持...")
    print("see you la la!")


# 创建一个插件对象 调用框架来使用它
# wincmd = plugins.WinCMD()
# 框架之外的部分就有自定义对象来完成

# 框架 得根据配置文件拿到需要的类

path = settings.CLASS_PATH
# 从配置中单独拿出来 模块路径和 类名称
module_path,class_name = path.rsplit(".",1)
#拿到模块
mk = importlib.import_module(module_path)
# 拿到类
cls = getattr(mk,class_name)
# 实例化对象
obj = cls()
#调用框架
run(obj)

class LinuxCMD:

    def cd(self):
        print("Linuxcmd 切换目录....")

    def rm(self):
        print("Linuxcmd 要不要删库跑路?")

    def ls(self):
        print("Linuxcmd 列出所有文件....")

动态导入importlib.import_module()的使用

import importlib

params = importlib.import_module('b.c.c') #绝对导入
params_ = importlib.import_module('.c.c',package='b') #相对导入

# 对象中取出需要的对象
params.args #取出变量
params.C  #取出class C
params.C.c  #取出class C 中的c 方法

元类 metaclass

什么元类??

源自一句话 :一切皆对象,而对象是有类实例化得到的 既然一切皆对象 那么我们平时创建的类 也是一个对象 只要是对象 那么都是调用一个类实例化得到的

class Teather:
    pass
# 那么这个teather也是一个对象 但是 他也是调用一个类得到的 这个类就是元类

这个元类是内置的 我们可以通过type()来查看一下他的类是啥

type(Teather) >>> <class 'type'>
# 所以说元类就是 type!!!

元类就是type 关系 调用元类 >>>自定义类 自定义类>>>对象

class底层的工作原理 teather = type(.......)

自定义类的三个关键组成部分

1.类名

2.类的基类

3.类的名称空间(属性)

那么 其实type元类接受的参数就是这三个关键的组成部分 其实就是调用type把三个关键的部分传进去 实例化得到的结果就是你得到的类 1 拿到类名(teather) 2.拿到类的基类(object) 3. 拿到名称空间(执行类体代码 将产生的名称放到一个字典里 ) 4调用元类实例化 得到类

自定义元类控制类的产生

但凡继承了type的类 就能称之为自定义的元类 否子就是一个普通的类

#  算是一个模板

class Mymeta(type): #但凡继承了type的类 就能称之为自定义的元类 否子就是一个普通的类
    def __init__(self, calss_name, class_bases, calss_dict):
        pass # self 就是Oldboy  他现在是一个对象  

class Oldboy(object, metaclass=Mymeta): #Oldboy = Mymeta('Oldboy', (object,), ....)   调用,mymeta 实例化oldboy  传入Mymeta  
    # 改的是元类
    school = 'Oldboy'  
    def __init__(self,name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
#控制类名必须驼峰体
class Mymeta(type): 
    def __init__(self, calss_name, class_bases, calss_dict):
        if class_name.islower():
            raise TypeError('必须使用驼峰体')
            
class Oldboy(object, metaclass=Mymeta):
    school = 'Oldboy'  
    def __init__(self,name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

doc 控制类的文档注释 在名称空间里

以上是关于反射 动态导入 元类的主要内容,如果未能解决你的问题,请参考以下文章

iOS中类元类isa详解

python元类深入解析

1104课堂小结

096 元类

面向对象之元类

面向对象-元类