Python: подкласс `type` для создания специализированных типов (например,« список int »)

StackOverflow https://stackoverflow.com/questions/6332342

  •  27-10-2019
  •  | 
  •  

Вопрос

Я пытаюсь создать подкласс 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. Если он не будет принят, он будет проигнорирован.

Как и раньше, классы, созданные фабрикой, кэшируются, поэтому каждый раз, когда вы вызываете класс с одинаковыми функциями, вы получаете один и тот же экземпляр объекта класса.

родовое слово

Пример класса списка с ограниченным типом (преобразование типа):

родовое слово

Создание новых классов:

родовое слово

Затем создайте экземпляр:

родовое слово

Или просто создайте класс и создайте его экземпляр за один шаг:

родовое слово
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top