J'essaie d'apprendre le python et je suis tombé sur du code qui est beau et court mais qui n'a pas totalement de sens
le contexte était:
def fn(*args):
return len(args) and max(args)-min(args)
Je comprends ce qu'il fait, mais pourquoi python fait-il cela - c'est-à-dire renvoie la valeur plutôt que True / False?
10 and 7-2
renvoie 5. De même, changer le et en ou entraînera une modification de la fonctionnalité. Alors
10 or 7 - 2
J'y retournerais 10.
Est-ce que ce style est légitime / fiable, ou y a-t-il des pièges à ce sujet?
and
(ainsi queor
) ne se limite pas à travailler avec ou à renvoyer des valeurs booléennes.None
ou une exception)0
vous ne pouvez pas dire s'ilargs
était vide ou non, mais que tous les éléments étaient égaux.Réponses:
TL; DR
Nous commençons par résumer les deux comportements des deux opérateurs logiques
and
etor
. Ces expressions idiomatiques formeront la base de notre discussion ci-dessous.Le comportement est également résumé dans la documentation , en particulier dans ce tableau:
Le seul opérateur renvoyant une valeur booléenne indépendamment de ses opérandes est l'
not
opérateur.Évaluations "Vérité" et "Vérité"
La déclaration
Est une manière très
pythoniqueconcise (et sans doute moins lisible) de dire "si ceargs
n'est pas vide, renvoie le résultat demax(args) - min(args)
", sinon retourne0
. En général, il s'agit d'une représentation plus concise d'uneif-else
expression. Par exemple,Devrait (à peu près) se traduire par:
Ou équivalent,
De même,
Est équivalent à,
Où
exp1
etexp2
sont des objets Python arbitraires ou des expressions qui renvoient un objet. La clé pour comprendre les utilisations des opérateurs logiquesand
etor
ici est de comprendre qu'ils ne se limitent pas à fonctionner ou à renvoyer des valeurs booléennes. Tout objet avec une valeur de vérité peut être testé ici. Cela inclutint
,str
,list
,dict
,tuple
,set
,NoneType
et objets définis par l' utilisateur. Les règles de court-circuit s'appliquent également.Mais qu'est-ce que la vérité?
Il fait référence à la manière dont les objets sont évalués lorsqu'ils sont utilisés dans des expressions conditionnelles. @Patrick Haugh résume bien la vérité dans cet article .
Comment
and
fonctionneNous nous appuyons sur la question d'OP comme une suite dans une discussion sur la façon dont ces opérateurs dans ces cas.
Trouver le minimum et le maximum est facile (utilisez les fonctions intégrées!). Le seul hic ici est de gérer correctement le cas du coin où la liste d'arguments pourrait être vide (par exemple, appeler
foo()
). Nous pouvons faire les deux en une seule ligne grâce à l'and
opérateur:Depuis
and
est utilisé, la deuxième expression doit également être évaluée si la première l'estTrue
. Notez que, si la première expression est évaluée comme véridique, la valeur de retour est toujours le résultat de la deuxième expression . Si la première expression est évaluée comme étant Falsy, le résultat renvoyé est le résultat de la première expression.Dans la fonction ci-dessus, If
foo
reçoit un ou plusieurs arguments,len(args)
est supérieur à0
(un nombre positif), le résultat renvoyé est doncmax(args) - min(args)
. OTOH, si aucun argument n'est passé,len(args)
est0
ce qui est Falsy et0
est retourné.Notez qu'une autre façon d'écrire cette fonction serait:
Ou, plus brièvement,
Si bien sûr, aucune de ces fonctions n'effectue de vérification de type, donc à moins que vous ne fassiez entièrement confiance à l'entrée fournie, ne vous fiez pas à la simplicité de ces constructions.
Comment
or
fonctionneJ'explique le fonctionnement de
or
de la même manière avec un exemple artificiel.Nous utilisons
or
pour gérer le cas d'angle ici. Nous définissonsfoo
comme:foo
effectue une filtration sur la liste pour conserver tous les numéros9000
. S'il existe de tels nombres, le résultat de la compréhension de la liste est une liste non vide qui est Vérité, donc elle est retournée (court-circuit en action ici). S'il n'existe pas de tels nombres, alors le résultat de la liste comp est[]
qui est Falsy. Ainsi, la deuxième expression est maintenant évaluée (une chaîne non vide) et est renvoyée.En utilisant des conditions, nous pourrions réécrire cette fonction comme suit:
Comme précédemment, cette structure est plus flexible en termes de gestion des erreurs.
la source
if ... else (if ... else (if ... else (if ... else ...)))
peut tout aussi bien être réécrit que... and ... and ... and ... and ...
et à ce stade, il devient vraiment difficile d'argumenter la lisibilité dans les deux cas.Citations à partir de documents Python
C'est ainsi que Python a été conçu pour évaluer les expressions booléennes et la documentation ci-dessus nous donne un aperçu de la raison pour laquelle ils l'ont fait.
Pour obtenir une valeur booléenne, transformez-la simplement.
Pourquoi?
Court-circuit.
Par exemple:
Il en va de
or
même, c'est-à-dire qu'il renverra l'expression qui est Vérité dès qu'il la trouve, car l'évaluation du reste de l'expression est redondante.Au lieu de retourner hardcore
True
ouFalse
, Python retourne Truthy ou Falsey , qui vont de toute façon évaluerTrue
ouFalse
. Vous pouvez utiliser l'expression telle quelle, et cela fonctionnera toujours.Pour savoir ce qui est Truthy et Falsey , consultez la réponse de Patrick Haugh
la source
et et ou exécutent une logique booléenne, mais ils renvoient l'une des valeurs réelles lors de la comparaison. Lors de l'utilisation de et , les valeurs sont évaluées dans un contexte booléen de gauche à droite. 0, '', [], (), {} et None sont faux dans un contexte booléen; tout le reste est vrai.
Si toutes les valeurs sont vraies dans un contexte booléen, et renvoie la dernière valeur.
Si une valeur est fausse dans un contexte booléen et renvoie la première valeur fausse.
Donc le code
renvoie la valeur de
max(args)-min(args)
quand il y a des arguments sinon elle retournelen(args)
qui est 0.la source
C'est légitime, c'est une évaluation de court-circuit où la dernière valeur est retournée.
Vous donnez un bon exemple. La fonction retournera
0
si aucun argument n'est passé, et le code n'a pas à vérifier un cas particulier sans argument passé.Une autre façon d'utiliser cela, est de définir par défaut les arguments None sur une primitive mutable, comme une liste vide:
Si une valeur non véridique lui est transmise par
alist
défaut, une liste vide, moyen pratique d'éviter uneif
instruction et le piège de l'argument mutable par défautla source
Gotchas
Oui, il y a quelques pièges.
fn() == fn(3) == fn(4, 4)
Premièrement, si
fn
retourne0
, vous ne pouvez pas savoir s'il a été appelé sans aucun paramètre, avec un paramètre ou avec plusieurs paramètres égaux:Que veut
fn
dire?Ensuite, Python est un langage dynamique. Il n'est spécifié nulle part ce que
fn
fait, ce que devrait être son entrée et à quoi devrait ressembler sa sortie. Par conséquent, il est vraiment important de nommer la fonction correctement. De même, les arguments n'ont pas besoin d'être appelésargs
.delta(*numbers)
oucalculate_range(*numbers)
pourrait mieux décrire ce que la fonction est censée faire.Erreurs d'argument
Enfin, l'
and
opérateur logique est censé empêcher la fonction d'échouer si elle est appelée sans aucun argument. Cela échoue toujours si un argument n'est pas un nombre, cependant:Alternative possible
Voici une façon d'écrire la fonction selon le "Plus facile de demander pardon que la permission". principe :
Par exemple:
Si vous ne voulez vraiment pas lever d'exception lors de l'
delta
appel sans aucun argument, vous pouvez retourner une valeur qui ne serait pas possible autrement (par exemple-1
ouNone
):la source
Je voudrais ajouter à cette question qu'il est non seulement légitime et fiable, mais aussi ultra pratique. Voici un exemple simple:
Par conséquent, vous pouvez vraiment l'utiliser à votre avantage. Pour être conscient, voici comment je le vois:
Or
opérateurL'
or
opérateur de Python renvoie la première valeur Truth-y, ou la dernière valeur, et s'arrêteAnd
opérateurL'
and
opérateur de Python renvoie la première valeur False-y, ou la dernière valeur, et s'arrêteDans les coulisses
En python, tous les nombres sont interprétés comme
True
sauf 0. Par conséquent, en disant:est le même que:
Ce qui est clairement
False
. Il est donc logique qu'il renvoie 0la source
Oui. C'est le comportement correct et la comparaison.
Au moins dans le python, les
A and B
rendementsB
seA
sont essentiellementTrue
compris siA
est non nulle, NENone
PAS un récipient vide (tel qu'un videlist
,dict
etc.).A
est renvoyé IFFA
est essentiellementFalse
ouNone
ou Empty ou Null.D'autre part, les
A or B
rendementsA
seA
sont essentiellementTrue
compris siA
est non nul, NENone
PAS un récipient vide (comme un videlist
,dict
etc.), sinon il retourneB
.Il est facile de ne pas remarquer (ou d'oublier) ce comportement car, en Python, tout
non-null
objet non vide évalué à True est traité comme un booléen.Par exemple, tout ce qui suit affichera "True"
Par contre, tout ce qui suit affichera "Faux"
la source
A
c'est essentiellementTrue
. Corrigée.pour comprendre de manière simple,
ET :
if first_val is False return first_val else second_value
par exemple:
mais,
et => si quelqu'un est faux, ce sera faux. si les deux sont vrais alors seulement cela deviendra vrai
OU :
if first_val is False return second_val else first_value
la raison est que si first est faux, il vérifie si 2 est vrai ou non.
par exemple:
mais,
ou => si quelqu'un est faux, ce sera vrai. donc si la première valeur est fausse, quelle que soit la valeur 2 supposée. il renvoie donc une seconde valeur quelle qu'elle soit.
si quelqu'un est vrai, cela deviendra vrai. si les deux sont faux, cela deviendra faux.
la source