Расширение типа int в Python для приема только значений в заданном диапазоне - PullRequest
4 голосов
/ 14 апреля 2010

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

myType = MyCustomInt(minimum=7, maximum=49, default=10)
i = myType(16)    # OK
i = myType(52)    # raises ValueError
i = myType()      # i == 10

positiveInt = MyCustomInt(minimum=1)     # no maximum restriction
negativeInt = MyCustomInt(maximum=-1)    # no minimum restriction
nonsensicalInt = MyCustomInt()           # well, the same as an ordinary int

Любая подсказка приветствуется. Спасибо!

Ответы [ 4 ]

5 голосов
/ 14 апреля 2010

Используйте __new__, чтобы переопределить конструкцию неизменяемых типов:

def makeLimitedInt(minimum, maximum, default):
    class LimitedInt(int):
        def __new__(cls, x= default, *args, **kwargs):
            instance= int.__new__(cls, x, *args, **kwargs)
            if not minimum<=instance<=maximum:
                raise ValueError('Value outside LimitedInt range')
            return instance
    return LimitedInt
1 голос
/ 14 апреля 2010

Нет необходимости определять новый тип:

def restrict_range(minimum=None, maximum=None, default=None, type_=int):
    def restricted(*args, **kwargs):
        if default is not None and not (args or kwargs): # no arguments supplied
            return default
        value = type_(*args, **kwargs)
        if (minimum is not None and value < minimum or 
            maximum is not None and value > maximum):
            raise ValueError
        return value
    return restricted

Пример

restricted_int = restrict_range(7, 49, 10)

assert restricted_int("1110", 2) == 14
assert restricted_int(16) == 16
assert restricted_int() == 10
try: 
    restricted_int(52)
    assert 0
except ValueError:
    pass
1 голос
/ 14 апреля 2010

Назначение в Python является оператором, а не выражением, поэтому нет способа определить назначение для типа, так как назначение полностью повторяет привязку имени. Лучшее, что вы можете сделать, - это определить метод set(), который принимает желаемое значение, и в этот момент вы можете просто создать «обычный» класс для обработки проверки.

0 голосов
/ 14 апреля 2010

Вы можете получить класс из int в Python, например. class MyInt(int), но этот тип в python неизменен (вы не можете изменить значение) после его создания.

Вы можете сделать что-то вроде этого:

class MyInt:
    def __init__(self, i, max=None, min=None):
        self.max = max
        self.min = min
        self.set(i)

    def set(self, i):
        if i > self.max: raise ValueError
        if i < self.min: raise ValueError
        self.i = i

    def toInt(self):
        return self.i

    def __getattr__(self, name):
        # Forward e.g. addition etc operations to the integer
        #   Beware that e.g. going MyInt(1)+MyInt(1) 
        #   will return an ordinary int of "2" though
        #   so you'd need to do something like 
        #   "result = MyInt(MyInt(1)+MyInt(1))

        method = getattr(self.i, name)
        def call(*args):
            L = []
            for arg in args:
                if isinstance(arg, MyInt):
                    L.append(arg.toInt())
                else: L.append(arg)
            return method(*L)
        return call

Может быть лучше использовать обычные функции проверки в зависимости от того, что вы хотите, хотя, если это проще.

РЕДАКТИРОВАТЬ : работает сейчас - Возврат к более простой более ранней версии, с добавлением и т.д. функций, которые возвращают другие экземпляры MyInt, просто не стоит: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...