简体   繁体   中英

How to add a base class automatically?

Introduction: A package xy defines a Node class (names are not real). Multiple nodes create a graph-like structure that the package does interesting things with. Basic example:

node0 = xy.Node(... some arguments here ...)

Nodes can have optional features. This is currently implemented with add-on/mix-in classes. Something like that:

class NodeF7(xy.Feature7, xy.Node):
    pass

node1 = NodeF7(..., feature7_timeout=5)
  1. the package user can now specify feature7 related values
  2. the package itself enables calls to the feature's methods in its internal code, because isinstance(node1, xy.Feature7) test is true.

Problem: Very often it is necessary to define a new class just to create a single instance of it. I'm thinking about simplifiyng the usage to just:

node1 = xy.Node(..., feature7_timeout=5)

ie when the Node class encounters any feature7 related parameter, it should automatically include the Feature7 class add-on. It is important, that isinstance(node1, xy.Feature7) becomes true.

I would like to ask how to implement that in the package. Is there a design pattern for this?

  • I'm sure a class factory function would work, but
  • maybe some abstract base class (ABC) related tricks would solve it in an elegant way,
  • or perhaps some clever code in the __new__ function?

First, we prepare a way to register features.

feature_registry = {}


def register_feature(*parameters):
    def decorator(cls):
        for parameter in parameters:
            feature_registry[parameter] = cls
        return cls
    return decorator


@register_feature('feature7_timeout')
class Feature7:
    def __init__(self, *args, feature7_timeout=None, **kwargs):
        print('feature7_timeout:', feature7_timeout)

    def feature7(self):
        assert isinstance(self, Feature7)

Then, in the __new__ function, we get the feature classes and create a new type.

class Node:

    def __new__(cls, *args, **kwargs):
        feature_classes = {feature_registry.get(k) for k in kwargs}
        feature_classes.discard(None)
        cls = type(cls.__name__, (*feature_classes, cls), {})
        return super().__new__(cls)

Usage:

node1 = Node(feature7_timeout=5)
node1.feature7()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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