Как я могу создать ограниченный int в Python? - PullRequest
0 голосов
/ 20 июня 2019

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

Например, если нижняя граница равна 2, то a = MyClass(1) должно вызвать исключение.

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

Как мне это сделать?

Ответы [ 2 ]

0 голосов
/ 20 июня 2019

Это сразу, не так много ошибок обрабатывается.

class boundedInt:

    def __init__(self, lower, upper):
        self.x = None
        if (lower <= upper):
            self.lower = lower
            self.upper = upper
        else:
            raise ValueError("Lower Bound must be lesser than Upper Bound".format())  

    def assign(self, x):
        if (x>= self.lower and x<=self.upper):
            self.x = x
            return self.x
        else:
            raise ValueError("Not in bounds")

myInt = boundedInt(15,20) # create object myInt
f = myInt.assign(17) # assigns value to a variable
0 голосов
/ 20 июня 2019

Попробуй это. Должно работать как на int с, так и на float с:

def BoundedNumber(number_class):
    def BoundedNumberClassCreator(class_name, lower_bound, upper_bound):
        if upper_bound and lower_bound and upper_bound < lower_bound:
            raise ValueError(f"Upper bound {upper_bound} is lower than the lower bound {lower_bound}")

        def new(cls, number):
            if lower_bound and number < lower_bound:
                raise ValueError(f"{number} is below the lower bound of {lower_bound} for this class")

            if upper_bound and upper_bound < number:
                raise ValueError(f"{number} is above the upper bound of {upper_bound} for this class")

            return number_class(number)

        return type(class_name, (number_class,),
                    {"__new__": new,
                     "__doc__": f"Class that acts like `{number_class.__name__}` but has an inclusive lower bound of {lower_bound} and an inclusive upper bound of {upper_bound}",
                     "lower_bound": lower_bound,
                     "upper_bound": upper_bound})

    return BoundedNumberClassCreator

BoundedInt = BoundedNumber(int)
BoundedFloat = BoundedNumber(float)

if __name__ == "__main__":
    IntBetween50And150 = BoundedInt('IntBetween50And150', 50, 150)
    print(IntBetween50And150(100) == 100)  # True
    try:
        IntBetween50And150(200)
    except ValueError as e:
        print(f"Caught the ValueError: {e}")  # Caught the value error: 200 is above the upper bound of 150 for this class

    print(IntBetween50And150(50.5))  # 50
    print(IntBetween50And150.__doc__) # Class that acts like `int` but has an inclusive lower bound of 50 and an inclusive upper bound of 150

Сложность с подклассами из int заключается в том, что она не имеет функции __init__. Вместо этого вы должны использовать функцию __new__.

Класс BoundedNumber заботится об этом, определяя функцию __new__, которая одновременно выполняет функцию int (или float) __new__, вызывая int (или float), но также перед этим выполняет свои собственные проверки границ.

Поскольку мы хотим динамически создать новый класс, нам нужно использовать функцию type. Это позволит нам создать новый класс с любыми границами, которые мы хотим во время выполнения.

Технически, чтобы ответить на ваш вопрос, вам нужно только вставить BoundedNumberClassCreator с int везде, где используется number_class, но, поскольку он работает и для float s, я решил, что инкапсулирую это чтобы уменьшить дубликат кода.

Одна странная вещь в этом решении, если вы ZeroToOne = BoundedInt('ZeroToOne', 0, 1) и затем создадите i = ZeroToOne(1.1), оно выдаст ошибку, даже если int(1.1) находится в пределах указанного диапазона. Если вам не нравится эта функция, вы можете поменять местами порядок чеков и возврата в методе new BoundedNumberClassCreator.

...