【问题标题】:How to create a scripting system for a class in python? [closed]如何为python中的类创建脚本系统? [关闭]
【发布时间】:2021-07-08 22:20:58
【问题描述】:

我想知道是否可以创建一个包含诸如以下函数的对象:

class Script:
    def update(self):
        print(True)

我可以将它添加到父类中,比如这个:

class Engine:
    def __init__(self):
        self.scripts = [Script()]

如何让脚本列表中的所有脚本在每一帧都运行它们的功能?

【问题讨论】:

    标签: python class


    【解决方案1】:

    这看起来像是注册表模式的匹配项。基本上,您必须在某个地方保存您创建的所有“脚本”子类,以便以后执行它们。有几种方法可以解决它-这个相对简单-

    # main.py
    __registry = []
    
    def register_class(cls):
      __registry.append(cls)
    
    
    class Script:
      pass
    

     # subclass.py
        
        from main import Script, register
        
        @register
        class SubScript(Script):
          pass
    

    # runner.py
    from main import __registry
    
    for cls in __registry:
      cls.run()
    

    另一种方法是使用__init_subclass__方法将子类直接存储在注册表对象上-

    _subclasses = []
    
    
    class Script:
        def __init_subclass__(cls, **kwargs):
            _subclasses.append(cls)
    
        @classmethod
        def run_all(cls):
            for cls in _subclasses:
                cls.run()
    
    
    class SubScript(Script):
        @classmethod
        def run(cls):
            print("a")
    
    
    Script.run_all()
    

    最后的方法是做同样的事情,但使用元类(尽管神奇的 init 方法一直允许我从代码中删除元类,所以我可能更喜欢这样做)

    所有三种方法的一个警告 - 如果一个文件没有被导入,注册表不知道它。您可以将代码放入主文件以搜索目录并导入所有模块,但这不会自动发生。

    【讨论】:

      【解决方案2】:

      如果它们是主类的子类,您可以动态导入模块类并执行它们的 run() 方法。

      这是一个例子:

      具有这种树结构:

      .
      ├── main.py
      ├── new_script.py
      └── script.py
      

      script.py:

      import os
      
      class Script:
          def run(self):
              print('Running Script class')
      
          def run_all(self):
              print('Running all scritps from Script class')
              # you can improve listing valid files for your case
              valid_files = [
                  k.split('.')[0] for k in os.listdir() if (
                      not k.startswith('__') and not k.endswith('__') and (
                          k != __file__.split(os.sep)[-1]
                      )
                  )
              ]
              for file_name in valid_files:
                  module = __import__(file_name)
                  # listing all attributes of the module
                  for k in dir(module):
                      cls = getattr(module, k)
                      # Check if cls have __name__ attribute
                      if hasattr(cls, '__name__'):
                          # the imported attribute should be a class
                          # and should not be the current module class
                          if isinstance(cls, type) and (
                              cls.__name__ != self.__class__.__name__
                          ):
                              # if the imported module is a subclass
                              # of the current class; then excecute run method
                              if issubclass(cls, self.__class__):
                                  cls.run(cls)
      

      new_script.py:

      from script import Script
      
      
      class NewScript(Script):
          def run(self):
              print('Running newScript')
      

      ma​​in.py:

      from script import Script
      
      
      if __name__ == '__main__':
          instance = Script()
          instance.run_all()
      

      演示:

      $> python main.py
      

      输出:

      Running all scritps from Script class
      Running newScript
      

      【讨论】:

      • 如果file_name = 'a.b.c' 您必须多次重新加载模块以指向最新的模块文件,例如:for k in file_name.split('.')[1:]: module = getattr(module, k)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      • 2022-10-04
      • 2015-10-02
      • 2014-04-25
      相关资源
      最近更新 更多