Материнский узор. Лучшие практики. Ввод текста

У меня есть следующие классы:

from abc import ABC, abstractmethod


class VarCharType(str, ABC):
    def __init__(self, value):
        self._validate_length(value)

    def _validate_length(self, value: str):
        if not self._min_length <= len(value) <= self._max_length:
            raise TypeError(f'Length must be between {self._min_length} and {self._max_length}')

    @property
    @abstractmethod
    def _min_length(self) -> int:
        pass

    @property
    @abstractmethod
    def _max_length(self) -> int:
        pass


class GivenName(VarCharType):
    _MIN_LENGTH = 1
    _MAX_LENGTH = 255

    @property
    def _min_length(self) -> int:
        return self._MIN_LENGTH

    @property
    def _max_length(self) -> int:
        return self._MAX_LENGTH


class FamilyName(VarCharType):
    ...

Чтобы протестировать свой код, я решил создать случайные значения FamilyName и GivenName с помощью шаблона Mother. Что-то вроде того:

class GivenNameMother:
    def random_max(self) -> GivenName:
        return GivenName(''.join(random.choices(string.ascii_uppercase, k=255)))
    
    def random_min(self) -> GivenName:
        return GivenName(''.join(random.choices(string.ascii_uppercase, k=1)))

class FamilyNameMother:
    def random_max(self) -> FamilyName:
        return FamilyName(''.join(random.choices(string.ascii_uppercase, k=255)))
    
    def random_min(self) -> FamilyName:
        return FamilyName(''.join(random.choices(string.ascii_uppercase, k=1)))

Предыдущая реализация имела несколько проблем:

  • Если GiveName меняет максимальную или минимальную длину, я должен изменить материнский класс. У меня есть некоторые сомнения, особенность это или проблема.
  • Для каждого дочернего класса VarCharType мне нужно создать материнский класс с более или менее одинаковым кодом. Проблема в том, что в какой-то момент я хочу протестировать символы utf-8, и мне придется изменить все материнские классы.

Я попробовал несколько решений, но они очень грязные, и мне это не нравится.

Каким было бы лучшее решение? Это требование, позволяющее избегать ввода Any из пакета ввода.

Спасибо!

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Прежде всего позвольте мне сказать, что это не идеальное решение. Вам все равно нужно будет выяснить, как именно вы хотите делиться информацией между классами, но это должно, по крайней мере, показать вам, как вы можете иметь общий NameMother, который по-прежнему будет поддерживать хорошую типизацию.

Итак, несколько замечаний:

  • Я добавил в класс заполнитель для _MIN_LENGTH и _MAX_LENGTH. Это связано с тем, что _min_length и _max_length настроены как методы экземпляра, а не как статические методы, поэтому они недоступны без экземпляра класса. Если мы создадим экземпляр, нам придется передать значение, и, не зная минимального или максимального значения, мы потенциально можем столкнуться с ошибкой ValueError.
  • Вы можете легко извлечь все «конфигурации» (например, случайные варианты) из класса типов, а не только мин/макс.
  • Они используют синтаксис и конструкции Python 3.11. Некоторые особенности могут отличаться, если вы используете более старую или новую версию, поскольку синтаксис типизации со временем значительно изменился.
import random
import string

from abc import ABC, abstractmethod
from typing import Generic, TypeVar


class VarCharType(str, ABC):
    _MIN_LENGTH: int
    _MAX_LENGTH: int

    def __init__(self, value: str) -> None:
        self._validate_length(value)

    def _validate_length(self, value: str) -> None:
        if not self._min_length <= len(value) <= self._max_length:
            raise TypeError(f'Length must be between {self._min_length} and {self._max_length}')

    @property
    @abstractmethod
    def _min_length(self) -> int:
        pass

    @property
    @abstractmethod
    def _max_length(self) -> int:
        pass


_T = TypeVar('_T', bound=VarCharType)


class NameMother(Generic[_T]):
    klass: type[_T]

    def __init__(self, klass: type[_T]) -> None:
        self.klass = klass

    def random_max(self) -> _T:
        return self.klass(''.join(random.choices(string.ascii_uppercase, k=self.klass._MAX_LENGTH)))

    def random_min(self) -> _T:
        return self.klass(''.join(random.choices(string.ascii_uppercase, k=self.klass._MIN_LENGTH)))


class GivenName(VarCharType):
    _MIN_LENGTH = 1
    _MAX_LENGTH = 255

    @property
    def _min_length(self) -> int:
        return self._MIN_LENGTH

    @property
    def _max_length(self) -> int:
        return self._MAX_LENGTH


given_name_mother = NameMother(GivenName)
print(given_name_mother.random_max())
print(given_name_mother.random_min())

Выход:

IESFIVCVYRPDBGQWQWWVVRHXQUSUJVDCUSFPEAFOPGENUWLQRSYDFJCUEVMFJXQVNJXFWQJWOLYVPBFROLHXZCIMYDYUGXBJNIYLZTVLWUBNWRLHDOGHJFHIQJSBHZPMPBSKXOJLGNLAKQVWGHKUTGQIEXCMCAKBGSBCZTCKHKGQXPLITMKHWHBQRAJBDYOVBGETGGUXVPNXLQGOGZGAPWTZZFEUXRFSNRCATRFGQBVYMDNNPZSXJOEZMSEYHDR
J

Другие вопросы по теме