简体   繁体   English

Python 创建派生实例 class

[英]Python create instance of derived class

I want to have abstract class Task and some derived classes like TaskA, TaskB, ... I need static method in Task fetching all the tasks and returning list of them.我想要抽象 class Task 和一些派生类,如 TaskA、TaskB,...我需要 static Task 中的方法来获取所有任务并返回它们的列表。 But problem is that I have to fetch every task differently.但问题是我必须以不同的方式获取每项任务。 I want Task to be universal so when I create new class for example TaskC it should work without changing class Task.我希望任务是通用的,所以当我创建新的 class 例如 TaskC 时,它应该可以在不更改 class 任务的情况下工作。 Which design pattern should I use?我应该使用哪种设计模式? Let's say every derived Task will have decorator with its unique id, I am looking for function that would find class by id and create instance of it.假设每个派生任务都有其唯一 ID 的装饰器,我正在寻找 function,它将通过 ID 找到 class 并创建它的实例。 How to do it in python? python怎么办?

There are a couple of ways you could achieve this.有几种方法可以实现这一点。

the first and most simple is using the __new__ method as a factory to decide what subclass should be returned.第一个也是最简单的方法是使用__new__方法作为工厂来决定应该返回哪个子类。

class Base:
    UUID = "0"
    def __new__(cls, *args, **kwargs):
        if args == "some condition":
            return A(*args, **kwargs)
        elif args == "another condition":
            return B(*args, **kwargs)

class A(Base):
    UUID = "1"

class B(Base):
    UUID = "2"
    
instance = Base("some", "args", "for", "the", condition=True)

in this example, if you wanted to make sure that the class is selected by uuid.在这个例子中,如果你想确保 class 被 uuid 选择。 you can replace the if condition to read something like你可以替换 if 条件来阅读类似的内容

if a.UUID == "an argument you passed":
    return A

but it's not really useful.但它并不是很有用。 since you have knowledge of the specific UUID, you might as well not bother going through the interface.既然您知道特定的 UUID,那么您不妨不必费心浏览该界面。

since I don't know what you want the decorator for, I can't think of a way to integrate it.因为我不知道你想要装饰器做什么,所以我想不出集成它的方法。

EDIT TO ADDRESS THE NOTE:编辑以解决注意事项:

you don't need to have update it every time, if you do your expressions smartly.如果你巧妙地表达你的表情,你不需要每次都更新它。

let's say that the defining factor comes from a config file, that says "use class B"假设定义因素来自配置文件,上面写着“使用 class B”

for sub_classs in self.__subclasses__():
    if sub_class.UUID == config.uuid:
        return sub_class(*args, **kwargs) # make an instance and return it

the problem with that is that uuid is not useful to us as people.这样做的问题是 uuid 对我们人类没有用。 it would be easier to understand if instead we used a config.name to replace every place we have uuid in the example如果我们使用config.name来替换我们在示例中有 uuid 的每个地方,将会更容易理解

I was fighting with this a lot of time and this is exactly what I wanted:我为此奋斗了很多时间,这正是我想要的:

def class_id(id:int):
    def func(cls):
        cls.class_id = lambda : id
        return cls
    return func

def find_subclass_by_id(cls:type, id:int) -> type:
    for t in cls.__subclasses__():
        if getattr(t, "class_id")() == id:
            return t


def get_class_id(obj)->int:
    return getattr(type(obj), "class_id")()



class Task():
    def load(self, dict:Dict) -> None:
        pass

    @staticmethod
    def from_dict(dict:Dict) -> 'Task':
        task_type = int(dict['task_type'])
        t = find_subclass_by_id(Task, task_type)
        obj:Task = t()
        obj.load(dict)
        return obj


    @staticmethod
    def fetch(filter: Dict):
        return [Task.from_dict(doc) for doc in list_of_dicts]

@class_id(1)
class TaskA(Task):
     def load(self, dict:Dict) -> None:
        ...
     ...
 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM