如何生成扩展子类?

zour9fqk  于 2021-08-20  发布在  Java
关注(0)|答案(2)|浏览(302)

关闭。这个问题需要更加关注。它目前不接受答案。
**想改进这个问题吗?**编辑这篇文章,更新这个问题,使它只关注一个问题。

昨天关门了。
改进这个问题
tldr:
3个文件:main.py、scriptclass.py、newscript.py
scriptclass:作为脚本蓝图的主类
newscript:scriptclass的一个子类示例
main:每帧运行scriptclass的所有子示例
如能提供这些文件的任何示例,将不胜感激
更短的tldr:除了脚本不是由游戏对象运行之外,如何在python中剽窃unity的脚本api
我无法将我的详细问题放在标题中,因此这里有更好的解释:我如何创建一种脚本类,如unity中的monobehavior,并基于该类创建新脚本?
基本上我想复制unity的脚本系统。我想以某种方式创建一个脚本类,如下所示:

class Script:
    def RunAllInstances():
        *run all child instances*
    def StartAllInstances():
        *start all child instances*

并在另一个文件中创建如下内容:

from script import Script
class NewScript(Script):
    def run():
        print(True)

并创建如下主文件:

from script import Script
Script.StartAllInstances()
while True:
    Script.RunAllInstances()

我知道monobehavior很重要,因为如果不将脚本类指定为monobehavior的子类,脚本将无法运行。这难道不意味着script类可以运行它的所有子类吗?unity(也许)通过将脚本作为一个组件,并让gameobjects运行其所有组件来处理这个问题。

yc0p9oo0

yc0p9oo01#

这看起来与注册表模式匹配。基本上,您必须将创建的所有“脚本”子类保存在某个位置,以便以后可以执行它们。有两种方法可以解决这个问题——这一种相对简单-


# 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()

最后一种方法是使用元类(尽管magic init方法一直允许我从代码中删除元类,所以我可能更喜欢这样)
这三种方法都有一个警告——如果一个文件没有被导入,注册表就不知道它。您可以将代码放入主文件中搜索目录并导入所有模块,但这不会自动发生。

wvyml7n5

wvyml7n52#

您可以动态导入模块类并执行它们的 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)

新建_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

相关问题