Python: подкласс `type` для создания специализированных типов (например,« список int »)
Вопрос
Я пытаюсь создать подкласс type
, чтобы создать класс, позволяющий создавать специализированные типы. например общий кодовый код:
Однако этот генерирующий код кода никогда не будет использоваться для создания экземпляров! Я просто использую его как экземпляр кода ListType
, которым я могу управлять для сравнения с другими типами ... В частности, в моем случае мне нужно найти подходящую операцию в соответствии с типом ввода, и мне нужен тип чтобы содержать больше точности (например, ListOfInt
или type
и т. д.).
Вот что я придумал:
родовое слово Использование list of int
неочевидно в приведенном выше коде ... однако, если я хочу написать подкласс XML string
, как в приведенном выше примере, это становится полезным ...
Базовая функциональность действительно работает:
родовое слово Но когда я пытаюсь проверить, является ли abc
экземпляром ListType
, Python приходит в ужас:
Я исследовал с помощью t
, что происходит, и обнаружил, что следующий код вызывает ошибку:
НАДЕЖНО ?! Очевидно, есть аргумент ... Так что это значит? Есть идеи ? Неправильно ли я использовал код генерирующего тега?
Решение 3
Благодаря комментарию kindall я изменил код на следующее:
родовое слово По сути, SpzType
теперь является подклассом abc.ABCMeta
, а subclasshook реализован как метод экземпляра.Он отлично работает и (ИМО) элегантен !!!
РЕДАКТИРОВАТЬ: возникла сложная вещь ... потому что __subclasshook__
должен быть методом класса, поэтому мне приходится вызывать функцию classmethod вручную ... иначе это не сработает, если я хочу реализовать __subclasshook__
.
Другие советы
Я не совсем понимаю, чего вы хотите достичь.Может быть, лучше использовать модуль collections
вместо прямого использования abc
?
Дополнительные сведения об общих классах коллекций см. в PEP 3119
То, что вы хотите сделать, вероятно, легче было бы сделать с помощью функции фабрики классов, подобной следующей.По крайней мере, для меня это упрощает четкое определение различных уровней, на которых я пытаюсь действовать.
родовое слово Обратите внимание, что здесь я использую код dict
в качестве кеша, чтобы вы получали один и тот же объект класса для данной комбинации типа элемента и функций.Это заставляет генерировать кодовый код всегда генерировать кодовый код.
Вот вариант декоратора моего другого ответа, который работает с любым классом. Декоратор возвращает фабричную функцию, которая возвращает подкласс исходного класса с желаемыми атрибутами. Преимущество этого подхода в том, что он не требует наличия метакласса, поэтому при желании вы можете использовать метакласс (например, ABCMeta
) без конфликтов.
Также обратите внимание, что если базовый класс использует метакласс, этот метакласс будет использоваться для создания экземпляра сгенерированного подкласса. Вы можете, если хотите, жестко запрограммировать желаемый метакласс или, знаете ли, написать декоратор, который превращает метакласс в декоратор для классов шаблонов ... это декораторы до конца!
Если он существует, метод класса __classinit__()
передает аргументы, переданные в фабрику, поэтому сам класс может иметь код для проверки аргументов и установки своих атрибутов. (Это будет вызываться после __init__()
метакласса.) Если __classinit__()
возвращает класс, этот класс возвращается фабрикой вместо сгенерированного, поэтому вы можете даже расширить процедуру генерации таким образом (например, для класса списка с проверкой типа , вы можете вернуть один из двух внутренних классов в зависимости от того, должны ли элементы быть приведены к типу элемента или нет).
Если __classinit__()
не существует, аргументы, переданные в фабрику, просто устанавливаются как атрибуты класса в новом классе.
Для удобства создания контейнерных классов с ограниченным типом я обработал тип элемента отдельно от функции dict. Если он не будет принят, он будет проигнорирован.
Как и раньше, классы, созданные фабрикой, кэшируются, поэтому каждый раз, когда вы вызываете класс с одинаковыми функциями, вы получаете один и тот же экземпляр объекта класса.
родовое словоПример класса списка с ограниченным типом (преобразование типа):
родовое словоСоздание новых классов:
родовое словоЗатем создайте экземпляр:
родовое словоИли просто создайте класс и создайте его экземпляр за один шаг:
родовое слово