Python实现动态实例化的示例代码

Written by

in

文章目录
  • 最近在查一个服务的问题时,看到有一段代码if .. elif … 写了近百行,类似 if command == “xxx”: obj = CommandX() obj.run() # … elif command == “yyy”: obj = CommandY() obj.run() # … elif command == “zzz”: obj = CommandZ() obj.run() # … # … 翻了下git记录,最开始其实只有两三个条件判断,后来command越加越多,就这么延续下来了。 代码逻辑其实没什么问题,也很简单明了,就是看起来有点丑,而且我还开了比较高的桌面缩放,导致一屏幕几乎都是这段if … elif 看来看去越发觉得丑,先写个demo看看能不能跑通代码。
  • 如果需要判断的条件比较少,用字典做映射还是挺方便的,但如果条件多,看起来还是挺丑的。 from abc import ABC, abstractmethod class AbstractCommand(ABC): @abstractmethod def run(self): pass class CommandA(AbstractCommand): def run(self): return “this is command A” class CommandB(AbstractCommand): def run(self): return “this is command B” class CommandC(AbstractCommand): def run(self): return “this is command C” class CommandFactory: @staticmethod def create_command(command_type: str) -> AbstractCommand: command_mapping = { “cmda”: CommandA, “cmdb”: CommandB, “cmdc”: CommandC } cls = command_mapping.get(command_type.lower()) if not cls: raise ValueError(f”Unknown command type: {command_type}”) return cls() if __name__ == “__main__”: cmd = CommandFactory.create_command(“cmda”) assert cmd.run() == “this is command A” cmd = CommandFactory.create_command(“cmdb”) assert cmd.run() == “this is command B” cmd = CommandFactory.create_command(“cmdc”) assert cmd.run() == “this is command CD” # should be exception cmd = CommandFactory.create_command(“cmdd”) # should be exception assert cmd.run() == “this is command D”
  • 《流畅的Python(第2版)》的最后一章提到了这个__init__subclass__,根据python官方文档: 当所在类派生子类时此方法就会被调用。cls 将指向新的子类。如果定义为一个普通实例方法,此方法将被隐式地转换为类方法。传给一个新类的关键字参数会被传给上级类的 __init_subclass__。 为了与其他使用 __init_subclass__ 的类兼容,应当去掉需要的关键字参数再将其他参数传给基类。 借助这个机制,可以在实现抽象基类时自动注册子类,避免手动维护注册表。 from abc import ABCMeta, abstractmethod from threading import Lock from collections import UserDict class ThreadSafeDict(UserDict): “””线程安全的字典””” def __init__(self): super().__init__() self._lock = Lock() def __setitem__(self, key, item): with self._lock: super().__setitem__(key, item) class Command(metaclass=ABCMeta): registry = ThreadSafeDict() def __init__(self): pass @abstractmethod def run(self): pass def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) cls.registry[cls.__name__.lower()] = cls # 自动注册子类 # 子类定义即自动注册 class CommandA(Command): def run(self): return “this is command a!” class CommandB(Command): def run(self): return “this is command b!” class CommandC(Command): def run(self): return “this is command b!” def create_command(command_type: str) -> Command: “””工厂函数””” cls = Command.registry.get(command_type.lower()) if not cls: raise ValueError(f”Unknown command type: {command_type}”) return cls() if __name__ == “__main__”: cmd = create_command(“CommandA”) assert cmd.run() == “this is command a!” cmd = create_command(“CommandB”) assert cmd.run() == “this is command b!” cmd = create_command(“CommandC”) assert cmd.run() == “this is command cc!” # should be exception cmd = create_command(“CommandD”) assert cmd.run() == “this is command b!” # should be exception 乍一看还是挺不错的,但是也有个缺点,那就是如果各个类分散在不同模块中,那么工厂函数所在的模块就要写一堆from xxx import … 如果module和类命名比较规范,也可以这么动态加载类 import importlib def create_class(module_name, class_name): module = importlib.import_module(module_name) cls = getattr(module, class_name) return cls()
  • 自动注册类看起来炫,但是对代码阅读来说不是很直观。易读还是美观?这是一个问题。 到此这篇关于Python实现动态实例化的示例代码的文章就介绍到这了,更多相关Python动态实例化内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: Python中类创建和实例化的过程详解 python实例化对象的具体方法 python类的实例化问题解决 Python面向对象程序设计中类的定义、实例化、封装及私有变量/方法详解 Python中类的创建和实例化操作示例 Python中实例化class的执行顺序示例详解 利用Python命令行传递实例化对象的方法
  • 目录
    • 前言
    • 方式1:字典映射
    • 方式2: __init_subclass__
    • 补充

    最近在查一个服务的问题时,看到有一段代码if .. elif ... 写了近百行,类似

    if command == "xxx":
    	obj = CommandX()
    	obj.run()
    	# ...
    elif command == "yyy":
    	obj = CommandY()
    	obj.run()
        # ...
    elif command == "zzz":
    	obj = CommandZ()
    	obj.run()
        # ...
    
    # ...
    

    翻了下git记录,最开始其实只有两三个条件判断,后来command越加越多,就这么延续下来了。

    代码逻辑其实没什么问题,也很简单明了,就是看起来有点丑,而且我还开了比较高的桌面缩放,导致一屏幕几乎都是这段if ... elif

    看来看去越发觉得丑,先写个demo看看能不能跑通代码。

    如果需要判断的条件比较少,用字典做映射还是挺方便的,但如果条件多,看起来还是挺丑的。

    from abc import ABC, abstractmethod
    
    class AbstractCommand(ABC):
        @abstractmethod
        def run(self):
            pass
    
    class CommandA(AbstractCommand):
        def run(self):
            return "this is command A"
        
    class CommandB(AbstractCommand):
        def run(self):
            return "this is command B"
        
    class CommandC(AbstractCommand):
        def run(self):
            return "this is command C"
        
    class CommandFactory:
        @staticmethod
        def create_command(command_type: str) -> AbstractCommand:
            command_mapping = {
                "cmda": CommandA,
                "cmdb": CommandB,
                "cmdc": CommandC
            }
            cls = command_mapping.get(command_type.lower())
            if not cls:
                raise ValueError(f"Unknown command type: {command_type}")
            return cls()
        
    if __name__ == "__main__":
        cmd = CommandFactory.create_command("cmda")
        assert cmd.run() == "this is command A"
    
        cmd = CommandFactory.create_command("cmdb")
        assert cmd.run() == "this is command B"
    
        cmd = CommandFactory.create_command("cmdc")
        assert cmd.run() == "this is command CD"  # should be exception
    
        cmd = CommandFactory.create_command("cmdd")  # should be exception
        assert cmd.run() == "this is command D"
    

    《流畅的Python(第2版)》的最后一章提到了这个__init__subclass__,根据python官方文档:

    当所在类派生子类时此方法就会被调用。cls 将指向新的子类。如果定义为一个普通实例方法,此方法将被隐式地转换为类方法。传给一个新类的关键字参数会被传给上级类的 __init_subclass__。 为了与其他使用 __init_subclass__ 的类兼容,应当去掉需要的关键字参数再将其他参数传给基类。

    借助这个机制,可以在实现抽象基类时自动注册子类,避免手动维护注册表。

    from abc import ABCMeta, abstractmethod
    from threading import Lock
    from collections import UserDict
    
    class ThreadSafeDict(UserDict):
        """线程安全的字典"""
        def __init__(self):
            super().__init__()
            self._lock = Lock()
        
        def __setitem__(self, key, item):
            with self._lock:
                super().__setitem__(key, item)
    
    class Command(metaclass=ABCMeta):
        registry = ThreadSafeDict()
    
        def __init__(self):
            pass
    
        @abstractmethod
        def run(self):
            pass
    
        def __init_subclass__(cls, **kwargs):
            super().__init_subclass__(**kwargs)
            cls.registry[cls.__name__.lower()] = cls  # 自动注册子类
    
    # 子类定义即自动注册
    class CommandA(Command):
        def run(self):
            return "this is command a!"
    
    class CommandB(Command):
        def run(self):
            return "this is command b!"
    
    class CommandC(Command):
        def run(self):
            return "this is command b!"
        
    def create_command(command_type: str) -> Command:
        """工厂函数"""
        cls = Command.registry.get(command_type.lower())
        if not cls:
            raise ValueError(f"Unknown command type: {command_type}")
        return cls()
        
    if __name__ == "__main__":
        cmd = create_command("CommandA")
        assert cmd.run() == "this is command a!"
        cmd = create_command("CommandB")
        assert cmd.run() == "this is command b!"
        cmd = create_command("CommandC")
        assert cmd.run() == "this is command cc!"  # should be exception
        cmd = create_command("CommandD")
        assert cmd.run() == "this is command b!"  # should be exception
    

    乍一看还是挺不错的,但是也有个缺点,那就是如果各个类分散在不同模块中,那么工厂函数所在的模块就要写一堆from xxx import ...

    如果module和类命名比较规范,也可以这么动态加载类

    import importlib
    
    def create_class(module_name, class_name):
        module = importlib.import_module(module_name)
        cls = getattr(module, class_name)
        return cls()
    

    自动注册类看起来炫,但是对代码阅读来说不是很直观。易读还是美观?这是一个问题。

    到此这篇关于Python实现动态实例化的示例代码的文章就介绍到这了,更多相关Python动态实例化内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

    您可能感兴趣的文章:

    • Python中类创建和实例化的过程详解
    • python实例化对象的具体方法
    • python类的实例化问题解决
    • Python面向对象程序设计中类的定义、实例化、封装及私有变量/方法详解
    • Python中类的创建和实例化操作示例
    • Python中实例化class的执行顺序示例详解
    • 利用Python命令行传递实例化对象的方法

    站内搜索