动态导入

运行时, 根据用户需求(提供字符串), 找到模块的资源进行动态的加载

# 内建函数 __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模块的能力
  • 多线程: 可以开启一个线程,等待用户输入,从而加载指定名称的模块

加载的时机

什么时候加载比较合适呢?

程序启动的时候, 还是程序运行中?

  1. 程序启动时

pycharm这样的工具, 需要很多组件, 这些组件也可能时插件, 启动的时候扫描固定的目录, 加载插件.

  1. 程序运行中

程序运行过程中, 接受用户指令或请求, 启动相应的插件.

两种加载方式各有利弊, 如果插件多, 会导致程序启动很慢, 如果用户需要时再加载, 如果插件太大或者依赖多, 插件也会启动慢.

所以先加载必须的, 常用的插件. 其他插件使用时, 发现需要再动态的载入.

__slots__

问题引出

字典为了提升查询效率, 必须用空间换时间,.一般来说一个对象,属性多一点, 都存储在字典中便于查询, 问题不大.但是如果数百万个对象,那么字典占的内存就有点大.

这个时候, 能不能把属性的字典__dict__省掉? 于是Python提供了__slots__

# 插槽
# 添加了 __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__只是控制了实例, 不会影响到类

__slots__不会影响到子类, 如果子类中需要__slots__, 需要自己定义

未实现和未实现异常

NotImplemented是一个单值None, 是NotImplementedType类的实例; NotImplementedError是一个异常

print(type(NotImplementedError))
print(type(NotImplemented))
# <class 'type'>
# # <class 'NotImplementedType'>

运算符重载中的反向方法

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 日 10 : 13 AM
如果觉得我的文章对你有用,请随意赞赏