Как сделать целое число больше любого другого целого? - программирование
Подтвердить что ты не робот

Как сделать целое число больше любого другого целого?

Примечание: в то время как принятый ответ достигает результата, который я хотел, а ответ @ecatmur предоставляет более полный вариант, я считаю очень важным подчеркнуть, что мой вариант использования - это плохая идея в первую очередь. Это объясняется очень хорошо в ответе @Jason Orendorff ниже.

Примечание: этот вопрос не является дубликатом вопроса о sys.maxint. Он не имеет ничего общего с sys.maxint; даже в python 2, где sys.maxint доступен, он НЕ представляет наибольшее целое число (см. принятый ответ).

Мне нужно создать целое число, большее, чем любое другое целое число, что означает объект int, который возвращает True по сравнению с любым другим объектом int, используя >. Случай использования: функция библиотеки ожидает целое число, и единственный простой способ заставить определенное поведение - передать очень большое целое число.

В python 2 я могу использовать sys.maxint (изменить: я ошибался). В python 3, math.inf является ближайшим эквивалентом, но я не могу преобразовать его в int.

4b9b3361

Ответ 1

Так как целые числа python неограничены, вы должны сделать это с помощью специального класса:

import functools

@functools.total_ordering
class NeverSmaller(object):
    def __le__(self, other):
        return False

class ReallyMaxInt(NeverSmaller, int):
    def __repr__(self):
        return 'ReallyMaxInt()'

Здесь я использовал класс mix-in NeverSmaller вместо прямого оформления ReallyMaxInt, потому что на Python 3 действие functools.total_ordering было бы предотвращено существующими методами упорядочения, унаследованными от int.

Демонстрация использования:

>>> N = ReallyMaxInt()
>>> N > sys.maxsize
True
>>> isinstance(N, int)
True
>>> sorted([1, N, 0, 9999, sys.maxsize])
[0, 1, 9999, 9223372036854775807, ReallyMaxInt()]

Обратите внимание, что в python2 sys.maxint + 1 больше, чем sys.maxint, поэтому вы не можете полагаться на это.

Отказ от ответственности: это целое число в смысле OO, оно не является целым числом в математическом смысле. Следовательно, арифметические операции, унаследованные от родительского класса int, могут не вести себя разумно. Если это вызывает какие-либо проблемы для вашего предполагаемого варианта использования, тогда их можно отключить, реализовав __add__ и друзей, чтобы просто выйти из системы.

Ответ 2

Konsta Vesterinen infinity.Infinity будет работать (pypi), за исключением того, что он не наследовать от int, но вы можете подклассифицировать его:

from infinity import Infinity
class IntInfinity(Infinity, int):
    pass
assert isinstance(IntInfinity(), int)
assert IntInfinity() > 1e100

Другим пакетом, который реализует значения "бесконечности", является Extremes, который был спасен от отклоненного PEP 326; опять же, вам потребуется подкласс от extremes.Max и int.

Ответ 3

Используйте случай: функция библиотеки ожидает целое число, и единственный простой способ заставить определенное поведение - передать очень большое целое число.

Это звучит как недостаток в библиотеке, который должен быть исправлен в его интерфейсе. Тогда все его пользователи выиграют. Что это за библиотека?

Создание магического подкласса int с переопределенными операторами сравнения может сработать для вас. Это хрупкое; вы никогда не знаете, что библиотека собирается делать с этим объектом. Предположим, что он преобразует его в строку. Что должно произойти? И данные, естественно, используются по-разному по мере развития библиотеки; вы можете обновить библиотеку в один прекрасный день, чтобы найти, что ваш трюк больше не работает.

Ответ 4

Мне кажется, что это было бы принципиально невозможно. Скажем, вы пишете функцию, которая возвращает этот RBI ( "действительно большой int" ). Если компьютер способен его хранить, то кто-то другой может написать функцию, которая возвращает одно и то же значение. Ваш RBI больше, чем он сам?

Возможно, вы можете достичь желаемого результата с помощью чего-то вроде ответа @wim: создать объект, который переопределяет операторы сравнения, чтобы сделать "<" всегда возвращайте false, а " > " всегда возвращает true. (Я не написал много Python.В большинстве объектно-ориентированных языков это будет работать, только если сравнение ставит ваше значение в первую очередь, IF RBI > x. Если кто-то пишет сравнение в другую сторону, IF x > RBI, it не удастся, потому что компилятор не знает, как сравнивать целые числа с определенным пользователем классом.)

Ответ 6

Вы не должны наследовать от int, если вы не хотите как его интерфейса, так и его реализации. (Его реализация представляет собой автоматически расширяющийся набор битов, представляющих конечное число. Вы явно не хотите этого.) Поскольку вам нужен только интерфейс, то наследуйте от ABC Integral. Благодаря ответу @ecatmur мы можем использовать infinity для решения проблемы бесконечности (включая отрицание). Вот как мы могли бы объединить infinity с ABC Integral:

import pytest
from infinity import Infinity
from numbers import Integral


class IntegerInfinity(Infinity, Integral):

    def __and__(self, other):
        raise NotImplementedError

    def __ceil__(self):
        raise NotImplementedError

    def __floor__(self):
        raise NotImplementedError

    def __int__(self):
        raise NotImplementedError

    def __invert__(self, other):
        raise NotImplementedError

    def __lshift__(self, other):
        raise NotImplementedError

    def __mod__(self, other):
        raise NotImplementedError

    def __or__(self, other):
        raise NotImplementedError

    def __rand__(self, other):
        raise NotImplementedError

    def __rlshift__(self, other):
        raise NotImplementedError

    def __rmod__(self, other):
        raise NotImplementedError

    def __ror__(self, other):
        raise NotImplementedError

    def __round__(self):
        raise NotImplementedError

    def __rrshift__(self, other):
        raise NotImplementedError

    def __rshift__(self, other):
        raise NotImplementedError

    def __rxor__(self, other):
        raise NotImplementedError

    def __trunc__(self):
        raise NotImplementedError

    def __xor__(self, other):
        raise NotImplementedError

def test():
    x = IntegerInfinity()
    assert x > 2
    assert not x < 3
    assert x >= 5
    assert not x <= -10
    assert x == x
    assert not x > x
    assert not x < x
    assert x >= x
    assert x <= x
    assert -x == -x
    assert -x <= -x
    assert -x <= x
    assert -x < x
    assert -x < -1000
    assert not -x < -x
    with pytest.raises(Exception):
        int(x)
    with pytest.raises(Exception):
        x | x
    with pytest.raises(Exception):
        ceil(x)

Это можно запустить с помощью pytest для проверки необходимых инвариантов.

Ответ 7

Другой способ сделать это (очень вдохновленный wim-ответом) может быть объектом, который не бесконечен, но увеличивается на лету по мере необходимости.

Вот что я имею в виду:

from functools import wraps

class AlwaysBiggerDesc():
    '''A data descriptor that always returns a value bigger than instance._compare'''
    def __get__(self, instance, owner):
        try:
            return instance._compare + 1
        except AttributeError:
            return instance._val
    def __set__(self, instance, value):
        try:
            del instance._compare
        except AttributeError:
            pass
        instance._val = value

class BiggerThanYou(int):
    '''A class that behaves like an integer but that increases as needed so as to be 
    bigger than "other" values. Defaults to 1 so that instances are considered
    to be "truthy" for boolean comparisons.'''
    val = AlwaysBiggerDesc()
    def __getattribute__(self, name):
        f = super().__getattribute__(name)
        try:
            intf = getattr(int,name)
        except AttributeError:
            intf = None
        if f is intf:
            @wraps(f)
            def wrapper(*args):
                try:
                    self._compare = args[1]
                except IndexError:
                    self._compare = 0 # Note: 1 will be returned by val descriptor
                new_bigger = BiggerThanYou()
                try:
                    new_bigger.val = f(self.val, *args[1:])
                except IndexError:
                    new_bigger.val =  f(self.val)
                return new_bigger
            return wrapper
        else:
            return f            
    def __repr__(self):
        return 'BiggerThanYou()'
    def __str__(self):
        return '1000...'

Что-то вроде этого могло бы избежать много странного поведения, которого можно было бы ожидать. Обратите внимание, что при таком подходе, если в операции задействованы два экземпляра BiggerThanYou, LHS будет считаться больше, чем RHS.

EDIT: в настоящее время это не работает. Я исправлю это позже. кажется, меня укусят функциональные возможности специальных методов поиска.