42 votes

En python, existe-t-il une sorte de mappage pour renvoyer la "valeur fausse" d'un type?

Je cherche une sorte de fonction de mappage f() qui fasse quelque chose de similaire à ceci:

 f(str) = ''
f(complex) = 0j
f(list) = []
 

Ce qui signifie qu'il renvoie un objet de type évalué à False lors de sa conversion en bool .

Une telle fonction existe-t-elle?

67voto

Aran-Fey Points 20414

Non, il n'y a pas une telle cartographie. Non chaque type d'objet a un falsy valeur, et d'autres ont plus d'un. Puisque la valeur de vérité d'une classe peuvent être personnalisés avec l' __bool__ méthode, une classe pourrait théoriquement avoir un nombre infini de (autre) falsy instances.

Cela dit, plus builtin types de retour de leur falsy valeur lors de leur constructeur est appelé sans arguments:

>>> str()
''
>>> complex()
0j
>>> list()
[]

26voto

juanpa.arrivillaga Points 35811

Non, et en général, il y a peut-être pas une telle valeur. Le Python, modèle de données est assez lâche sur la façon dont la valeur de vérité d'un type peut être mis en œuvre:

object.__bool__(self)

Appelés à mettre en œuvre vérité le test de la valeur et de l'exploitation intégré bool(); doit retourner False ou True. Lorsque cette méthode n'est pas définie, __len__() est appelée, si elle est définie, et l'objet est considérée comme vraie si son résultat est différent de zéro. Si une classe ne définit ni __len__() ni __bool__(), toutes ses instances sont considérées comme de vraies.

Donc prendre en compte:

import random
class Wacky:
    def __bool__(self):
        return bool(random.randint(0,1))

Que devrait - f(Wacky) de retour?

6voto

Karl Bielefeldt Points 15469

C'est en fait un élément de l'identité, et la programmation est le plus souvent considérée comme faisant partie de la définition d'un monoïde. En python, vous pouvez l'obtenir pour un type à l'aide de l' mzero fonction dans le PyMonad paquet. Haskell appelle mempty.

5voto

Mad Physicist Points 3218

Pas tous les types ont une telle valeur pour commencer avec. D'autres peuvent avoir beaucoup de ces valeurs. La plus correcte de le faire serait de créer un type de la valeur dict, parce que vous pouvez vérifier si un type donné est dans le dict à tous, et vous pourriez choisir la valeur est correcte s'il y a plusieurs options. L'inconvénient est bien sûr que vous devez en quelque sorte de s'inscrire à chaque type vous intéressait.

Alternativement, vous pouvez écrire une fonction à l'aide de quelques heuristiques. Si vous avez été très prudent sur ce que vous avez passé dans la fonction, il serait probablement d'une utilisation limitée. Par exemple, tous les cas de vous montrer à l'exception de complex sont des conteneurs généraliser avec cls().

complex fonctionne réellement comme ça aussi, mais je le mentionne séparément car, int et float ne le font pas. Donc, si votre tentative avec le constructeur vide échoue en retournant un truthy objet ou d'élever un TypeError, vous pouvez essayer d' cls(0). Et ainsi de suite et ainsi de suite...

Mise à jour

@juanpa.arrivillaga la réponse de fait suggère une astucieuse solution qui fonctionne pour la plupart des classes. Vous pouvez étendre la classe et la force de créer une instance qui sera falsy mais sinon identique à la classe d'origine. Vous devez faire cela en étendant parce que dsous méthodes comme __bool__ ne sont jamais penchés sur la classe, jamais sur une instance. Il existe de nombreux types là où de telles méthodes ne peuvent pas être remplacés sur l'instance pour commencer. Comme @Aran-Fey est désormais supprimé le commentaire de points, vous pouvez les appeler de manière sélective object.__new__ ou t.__new__, selon si vous êtes confronté à un cas très particulier (comme int) ou pas:

def f(t):
    class tx(t):
        def __bool__(self):
            return False
    try:
        return object.__new__(tx)
    except TypeError:
        return tx.__new__(tx)

Cela ne fonctionne que pour 99,9% des classes que vous rencontrerez jamais. Il est possible de créer un artificiel de cas qui soulève TypeError lorsqu'il est passé à l' object.__new__ comme int n', et ne permettent pas un no-arg version de t.__new__, mais je doute que vous trouverez jamais une telle chose dans la nature. Voir le gist @Aran-Fey a fait pour le démontrer.

2voto

Kafein Points 61

La fonction n'existe pas car il n'est pas possible en général. Une classe peut avoir aucune falsy valeur ou elle peut exiger la reprise d'une arbitrairement complexe la mise en œuvre de l' __bool__.

Ce que vous pourriez faire en brisant tout le reste est de construire un nouvel objet de cette classe et la force de céder ses __bool__ fonction de celui qui renvoie False. Bien que je soupçonne que vous êtes à la recherche d'un objet qui serait autrement un membre valide de la classe.

En tout cas, c'est une Très Mauvaise Idée dans un style classique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X