web-dev-qa-db-fra.com

Comment rendre un entier plus grand que n'importe quel autre entier?

Remarque: bien que la réponse acceptée atteigne le résultat que je voulais et que la réponse @ecatmur offre une option plus complète, je pense qu'il est très important de souligner que mon cas d'utilisation est une mauvaise idée en premier lieu. Ceci est très bien expliqué dans @ Jason Orendorff réponse ci-dessous .

Remarque: cette question n'est pas un doublon de la question sur sys.maxint . Cela n'a rien à voir avec sys.maxint; même dans python 2 où sys.maxint est disponible, il ne représente PAS le plus grand entier (voir la réponse acceptée).

Je dois créer un entier plus grand que tout autre entier, ce qui signifie un objet int qui renvoie True par rapport à tout autre objet int utilisant >. Cas d'utilisation: la fonction de bibliothèque attend un entier, et le seul moyen facile de forcer un certain comportement est de passer un entier très grand.

En python 2, je peux utiliser sys.maxint (modifier: j'avais tort). Dans python 3, math.inf est l'équivalent le plus proche, mais je ne peux pas le convertir en int.

50
max

Puisque python sont illimités, vous devez le faire avec une classe personnalisée:

import functools

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

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

Ici, j'ai utilisé une classe de mixage NeverSmaller plutôt qu'une décoration directe de ReallyMaxInt, car sur Python 3 l'action de functools.total_ordering aurait été empêché par les méthodes de classement existantes héritées de int.

Démo d'utilisation:

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

Notez qu'en python2, sys.maxint + 1 est plus grand que sys.maxint, vous ne pouvez donc pas vous fier à cela.

Clause de non-responsabilité : il s'agit d'un entier au sens OO , ce n'est pas un entier au sens mathématique. Par conséquent, les opérations arithmétiques héritées de la classe parente int peuvent ne pas se comporter correctement. Si cela pose des problèmes pour votre cas d'utilisation prévu, ils peuvent être désactivés en implémentant __add__ et mes amis pour faire une erreur.

67
wim

Konsta Vesterinen infinity.Infinity fonctionnerait ( pypi ), sauf qu'il n'hérite pas de int, mais vous pouvez le sous-classer:

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

Extremes , qui a été récupéré du --- PEP 326 ; encore une fois, vous devez sous-classe de extremes.Max et int.

27
ecatmur

Cas d'utilisation: la fonction de bibliothèque attend un entier, et le seul moyen facile de forcer un certain comportement est de passer un entier très grand.

Cela ressemble à une faille dans la bibliothèque qui devrait être corrigée dans son interface. Tous ses utilisateurs en bénéficieraient alors. De quelle bibliothèque s'agit-il?

La création d'une sous-classe int magique avec des opérateurs de comparaison remplacés peut fonctionner pour vous. C'est fragile, cependant; vous ne savez jamais ce que la bibliothèque va faire avec cet objet. Supposons qu'il le convertisse en chaîne. Que doit-il se passer? Et les données sont naturellement utilisées de différentes manières à mesure qu’une bibliothèque évolue; vous pouvez mettre à jour la bibliothèque un jour pour constater que votre astuce ne fonctionne plus.

15
Jason Orendorff

Il me semble que cela serait fondamentalement impossible. Disons que vous écrivez une fonction qui retourne ce RBI ("really big int"). Si l'ordinateur est capable de le stocker, quelqu'un d'autre pourrait écrire une fonction qui renvoie la même valeur. Votre RBI est-il supérieur à lui-même?

Vous pouvez peut-être obtenir le résultat souhaité avec quelque chose comme la réponse de @ wim: créez un objet qui remplace les opérateurs de comparaison pour que "<" renvoie toujours false et ">" renvoie toujours true. (Je n'ai pas écrit beaucoup de Python. Dans la plupart des langages orientés objet, cela ne fonctionnerait que si la comparaison place votre valeur en premier, IF RBI> x. Si quelqu'un écrit la comparaison dans l'autre sens, IF x> RBI, il échouera car le compilateur ne sait pas comparer les entiers à une classe définie par l'utilisateur.)

1
Jay

Dans Python 3.5, vous pouvez faire:

import math test = math.inf

Et alors:

test > 1 test > 10000 test > x

Sera toujours vrai. Sauf bien sûr, comme indiqué, x est également infini ou "nan" ("pas un nombre").

Comment puis-je représenter un nombre infini en Python?

Répondue par @WilHall

1
R__raki__

Vous ne devez pas hériter de int sauf si vous voulez à la fois son interface et son implémentation. (Son implémentation est un ensemble de bits à élargissement automatique représentant un nombre fini. Vous n'en voulez clairement pas.) Puisque vous ne voulez que interface, héritez ensuite de ABC Integral. Grâce à la réponse de @ ecatmur, nous pouvons utiliser infinity pour gérer le moindre détail de l'infini (y compris la négation). Voici comment combiner infinity avec 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)

Cela peut être exécuté avec pytest pour vérifier les invariants requis.

0
Neil G