Универсальные шаблоны / шаблоны в Python?

Как python обрабатывает общие сценарии / сценарии шаблонного типа? Скажем, я хочу создать внешний файл «BinaryTree.py» и заставить его обрабатывать двоичные деревья, но для любого типа данных.

Так что я мог передать ему тип настраиваемого объекта и получить двоичное дерево этого объекта. Как это делается в Python?

62
задан igaurav 13 October 2014 в 05:34
поделиться

1 ответ

Вот вариант этот ответ , который использует метаклассы, чтобы избежать грязного синтаксиса и использовать typing - стиль List[int] синтаксис:

class template(type):
    def __new__(metacls, f):
        cls = type.__new__(metacls, f.__name__, (), {
            '_f': f,
            '__qualname__': f.__qualname__,
            '__module__': f.__module__,
            '__doc__': f.__doc__
        })
        cls.__instances = {}
        return cls

    def __init__(cls, f):  # only needed in 3.5 and below
        pass

    def __getitem__(cls, item):
        if not isinstance(item, tuple):
            item = (item,)
        try:
            return cls.__instances[item]
        except KeyError:
            cls.__instances[item] = c = cls._f(*item)
            item_repr = '[' + ', '.join(repr(i) for i in item) + ']'
            c.__name__ = cls.__name__ + item_repr
            c.__qualname__ = cls.__qualname__ + item_repr
            c.__template__ = cls
            return c

    def __subclasscheck__(cls, subclass):
        for c in subclass.mro():
            if getattr(c, '__template__', None) == cls:
                return True
        return False

    def __instancecheck__(cls, instance):
        return cls.__subclasscheck__(type(instance))

    def __repr__(cls):
        import inspect
        return '<template {!r}>'.format('{}.{}[{}]'.format(
            cls.__module__, cls.__qualname__, str(inspect.signature(cls._f))[1:-1]
        ))

С этим новым метаклассом, мы можем переписать пример в ответе, с которым я связываюсь как:

@template
def List(member_type):
    class List(list):
        def append(self, member):
            if not isinstance(member, member_type):
                raise TypeError('Attempted to append a "{0}" to a "{1}" which only takes a "{2}"'.format(
                    type(member).__name__,
                    type(self).__name__,
                    member_type.__name__ 
                ))

                list.append(self, member)
    return List

l = List[int]()
l.append(1)  # ok
l.append("one")  # error

Этот подход обладает некоторыми хорошими преимуществами

print(List)  # <template '__main__.List[member_type]'>
print(List[int])  # <class '__main__.List[<class 'int'>, 10]'>
assert List[int] is List[int]
assert issubclass(List[int], List)  # True
0
ответ дан 24 November 2019 в 16:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: