【发布时间】:2021-07-08 22:20:58
【问题描述】:
我想知道是否可以创建一个包含诸如以下函数的对象:
class Script:
def update(self):
print(True)
我可以将它添加到父类中,比如这个:
class Engine:
def __init__(self):
self.scripts = [Script()]
如何让脚本列表中的所有脚本在每一帧都运行它们的功能?
【问题讨论】:
我想知道是否可以创建一个包含诸如以下函数的对象:
class Script:
def update(self):
print(True)
我可以将它添加到父类中,比如这个:
class Engine:
def __init__(self):
self.scripts = [Script()]
如何让脚本列表中的所有脚本在每一帧都运行它们的功能?
【问题讨论】:
这看起来像是注册表模式的匹配项。基本上,您必须在某个地方保存您创建的所有“脚本”子类,以便以后执行它们。有几种方法可以解决它-这个相对简单-
# 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 方法一直允许我从代码中删除元类,所以我可能更喜欢这样做)
所有三种方法的一个警告 - 如果一个文件没有被导入,注册表不知道它。您可以将代码放入主文件以搜索目录并导入所有模块,但这不会自动发生。
【讨论】:
如果它们是主类的子类,您可以动态导入模块类并执行它们的 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')
main.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)