Loading... ## 动态导入 运行时, 根据用户需求(提供字符串), 找到模块的资源进行动态的加载 ```python # 内建函数 __import__ __import__(name, globals=None, locals=None, fromlist=(), level=0) # name 模块名 # import 语句本质上就是调用这个函数, 但是不鼓励直接使用它, 建议使用下面的模块 import importlib importlib.import_module() sys = __import__('sys') # 等价 import sys # 下面就是插件化编程的核心部分 import importlib def load_module(string: str, sep='.'): mod, attr = string.rsplit(sep) mod = importlib.import_module(mod) return getattr(mod, attr) if __name__ == '__main__': timestamp = load_module('time.time') print(timestamp()) ``` ## 插件化编程技术 ### 依赖的技术 - 反射: 运行时获取类型的信息, 可以动态维护类型数据 - 动态`import`: 推荐使用`importlib`模块, 实现动态`import`模块的能力 - 多线程: 可以开启一个线程,等待用户输入,从而加载指定名称的模块 ### 加载的时机 <div class="tip inlineBlock warning"> 什么时候加载比较合适呢? </div> 程序启动的时候, 还是程序运行中? 1. 程序启动时 像`pycharm`这样的工具, 需要很多组件, 这些组件也可能时插件, 启动的时候扫描固定的目录, 加载插件. 2. 程序运行中 程序运行过程中, 接受用户指令或请求, 启动相应的插件. 两种加载方式各有利弊, 如果插件多, 会导致程序启动很慢, 如果用户需要时再加载, 如果插件太大或者依赖多, 插件也会启动慢. 所以先加载必须的, 常用的插件. 其他插件使用时, 发现需要再动态的载入. ## `__slots__` ### 问题引出 字典为了提升查询效率, 必须用空间换时间,.一般来说一个对象,属性多一点, 都存储在字典中便于查询, 问题不大.但是如果数百万个对象,那么字典占的内存就有点大. 这个时候, 能不能把属性的字典`__dict__`省掉? 于是`Python`提供了`__slots__` ```python # 插槽 # 添加了 __slots__ 属性, 就限制了实例的属性,且没有__dict__字段 class A: X = 123 __slots__ = ('p1', 'p2') def __init__(self): self.p1 = 12 self.p2 = 14 self.m = 1 # 当定义了__slots__, 这条语句会报错, 因为m没有包含在__slots__中 instance = A() instance.test = 12 # 这里会抛出异常, 因为test没有在__slots__中, 无法设置属性 print(instance.__dict__) # 这里也会抛出异常, 因为有了__slots__就不会产生dict print(instance.__slots__) # slots可以节省内存 instance.X = 200 # 这里也不可以进行修改, 因为实例的属性被__slots__控制了 A.X = 200 # 这里可以进行修改, 因为__slots__只是控制了实例, 不会影响到类 ``` <div class="tip inlineBlock info"> `__slots__`不会影响到子类, 如果子类中需要`__slots__`, 需要自己定义 </div> ## 未实现和未实现异常 `NotImplemented`是一个单值`None`, 是`NotImplementedType`类的实例; `NotImplementedError`是一个异常 ```python print(type(NotImplementedError)) print(type(NotImplemented)) # <class 'type'> # # <class 'NotImplementedType'> ``` ## 运算符重载中的反向方法 ```python class Add: def __init__(self, x): self.x = x def __add__(self, other): print('add') return self.__class__(self.x + int(other)) def __iadd__(self, other): print('iadd') self.x += int(other) return self def __radd__(self, other): """左边+右边, 左边没有实现add方法, 就调用右边的radd""" print('radd') return self + other def __str__(self): return str(self.x) def __int__(self): return self.x __repr__ = __str__ class B: def __init__(self, x): self.x = x def __int__(self): return self.x if __name__ == '__main__': a = Add(8) print(a + 1) print(a + Add(1)) a += Add(1) b = B(12) print(b + a) # b没有实现add方法, 于是就调用a的radd方法 # b + a 等价于 b.__add__(a) , 但是 b没有实现add方法, 于是就调用a的radd方法 # 1 + a 等价于 1.__add__(a) , 但是 int类型对于这种加法返回的是一个NotImplemented, 解释器发现是NotImplemented,就会调用右边的__radd__方法 ``` 最后修改:2021 年 06 月 09 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 1 如果觉得我的文章对你有用,请随意赞赏
1 条评论
哈哈哈,写的太好了https://www.lawjida.com/