Comportement étrange avec IN et OR...

6 réponses
Avatar
Dominique
Bonjour,

Je dois commettre une erreur, mais je ne vois pas laquelle. J'extrais
une unique ligne d'un fichier log :

test='[22118.286892] i915 0000:00:02.0: [drm] *ERROR* AUX C/DDI C
(TC)/PHY TC1: did not complete or timeout within 10ms (status 0xad4003ff)'

Si je fais :

'ERR' in test
Out[122]: True

Le TRUE est valable, car il y a bien le mot ERRROR.

Pour travailler sur des 'mots', je transforme mon string en une liste :

test2=list(test.split(' '))

On poursuit

test2[4]
Out[127]: '*ERROR*'

Tout est logique. Ensuite, je comprends moins bien :

'ERR' in test2
Out[129]: False

Or, '*ERROR*' in test2
Out[130]: True

D'accord, dans une liste, Python cherche une occurrence exacte. Si je
poursuis mes recherches :

'*ERROR*' or 'ERR' in test2
Out[131]: '*ERROR*'

Il me sort *ERROR* alors que je voulais simplement une sortie booléenne,
mais peu importe. Je remplace test2[4] avec 'essai' (je supprime
*ERROR*) et j'ajoute 'ERR' Í  test2 ;

test2[4]='essai' puis test2.append('ERR')
Test2 est correctement modifiée. Or, si je fais ça :

'*ERROR*' or 'ERR' in test2
Out[137]: '*ERROR*'

Il me retrouve le mot'*ERROR*' que j'ai supprimé et pas 'ERR' que j'ai
ajouté !

C'est d'autant plus étrange que 'ERRE' est bien trouvé :

'ERR' in test2
Out[138]: True

Qu'est-ce qui peut expliquer ce comportement ?

Je vous remercie pour votre éclairage,

Dominique

6 réponses

Avatar
Alain Ketterlin
Dominique writes:
test='[22118.286892] i915 0000:00:02.0: [drm] *ERROR* AUX C/DDI C
(TC)/PHY TC1: did not complete or timeout within 10ms (status
0xad4003ff)'
test2=list(test.split(' '))
'*ERROR*' or 'ERR' in test2

Cela ne signifie pas ce que tu crois. Cette expression est interprétée
comme :
- est-ce que « '*ERROR*' » est vraie ?
- sinon, est-ce que « 'ERR' in test2 » est vraie ?
Techniquement c'est
('*ERROR*') or ('ERR' in test2)
L'opérande de gauche ne mentionne même pas test2.
La première condition ('*ERROR*') est toujours vérifiée (parce qu'une
chaÍ®ne de caractères est considérée comme vraie dès qu'elle n'est pas
vide). D'autre part "x or y" a la valeur de x si x est vraie, et sinon
la valeur de y : en clair, une valeur brute (comme '*ERROR*') est
convertie en booléen pour tester sa véracité, mais l'expression garde la
valeur non convertie.
(Au passage, c'est une illustration de l'aversion de python pour le
typage. Par exemple le résultat de
x or "Damned"
o͹ x est un entier, sera soit un entier (si x != 0) soit une chaine de
caractères. Pure perversité.)
Bref : ce que tu veux (probablement) est
'*ERROR*' in test2 or 'ERR' in test2
Il faut faire deux tests "in", on ne peut pas tester deux valeurs en
même temps avec "in" : ce qui est Í  gauche de "in" doit être une chaÍ®ne
(dans ton cas). Si tu écris :
('*ERROR*' or 'ERR') in test2
le "or" est calculé d'abord, et tu testes en substance « '*ERROR*' in
test2 ».
-- Alain.
Avatar
Dominique
Le 26/05/2022 Í  10:29, Dominique a écrit :
Voici ma variable :
test2=['[22118.286892]', 'i915', '0000:00:02.0:', '[drm]',
'essai','AUX', 'C/DDI', 'C', '(TC)/PHY', 'TC1:', 'did', 'not',
'complete', 'or', 'timeout', 'within', '10ms', '(status', '0xad4003ff)',
'ERR']
J'ai compris mon erreur. J'utilisais mal OR :
'AUX' in test2 or 'essai' in test2
Out[193]: True
et 'AUX' in test2 and 'ERROR' in test2
Out[196]: False
Les deux réponses deviennent bonnes !
Désolé pour le bruit inutile... mais ça m'a fait progresser...
Bon long weekend pour ceux qui sont concernés,
Dominique
Avatar
Benoit Izac
Bonjour,
Le 26/05/2022 Í  10:29, Dominique a écrit dans le message
<t6ndp3$1igp$ :
Je dois commettre une erreur, mais je ne vois pas laquelle. J'extrais
une unique ligne d'un fichier log :
test='[22118.286892] i915 0000:00:02.0: [drm] *ERROR* AUX C/DDI C
(TC)/PHY TC1: did not complete or timeout within 10ms (status
0xad4003ff)'
Si je fais :
'ERR' in test
Out[122]: True
Le TRUE est valable, car il y a bien le mot ERRROR.

Car la chaÍ®ne de caractères contient bien «Â ERR » plus précisément.
Pour travailler sur des 'mots', je transforme mon string en une liste :
test2=list(test.split(' '))
On poursuit
test2[4]
Out[127]: '*ERROR*'
Tout est logique. Ensuite, je comprends moins bien :
'ERR' in test2
Out[129]: False

'ERR' n'est pas un éléments de la liste donc c'est normal.
Or, '*ERROR*' in test2
Out[130]: True

'*ERROR*' en est un.
D'accord, dans une liste, Python cherche une occurrence exacte. Si je
poursuis mes recherches :
'*ERROR*' or 'ERR' in test2
Out[131]: '*ERROR*'
Il me sort *ERROR* alors que je voulais simplement une sortie
booléenne, mais peu importe. Je remplace test2[4] avec 'essai' (je
supprime *ERROR*) et j'ajoute 'ERR' Í  test2 ;

Ce que tu veux c'est :
'*ERROR*' in test2 or 'ERR' in test2
ou encore :
any(s in test2 for s in ['*ERROR*', 'ERR'])
test2[4]='essai' puis test2.append('ERR')
Test2 est correctement modifiée. Or, si je fais ça :
'*ERROR*' or 'ERR' in test2
Out[137]: '*ERROR*'
Il me retrouve le mot'*ERROR*' que j'ai supprimé et pas 'ERR' que j'ai
ajouté !
C'est d'autant plus étrange que 'ERRE' est bien trouvé :
'ERR' in test2
Out[138]: True
Qu'est-ce qui peut expliquer ce comportement ?
'foo' or 'bar'



'foo'
'bar' or 'foo'



'bar'
False or 'foo'



'foo'
False or False



False
Le «Â or » renvoie la première occurrence qui n'est pas fausse. Une
chaÍ®ne de caractère non vide est toujours vrai.
--
Benoit Izac
Avatar
Dominique
Le 26/05/2022 Í  11:27, Alain Ketterlin a écrit :
Merci Alain,
C'est la conclusion Í  laquelle je suis parvenu (mauvaise utilisation de OR)
Merci pour l'ensemble de tes précisons.
Je ne connaissais pas cette subtilité :
if 'ERROR':
print('OK')
OK
même si ERROR n'esst pas défini.
Et en poussant un peu :
if not 'ERROR':
print('Non')
else:
print('OK')
OK
Bref : ce que tu veux (probablement) est
'*ERROR*' in test2 or 'ERR' in test2

Oui, c'était exactement ça :-)
Il faut faire deux tests "in", on ne peut pas tester deux valeurs en
même temps avec "in" : ce qui est Í  gauche de "in" doit être une chaÍ®ne
(dans ton cas). Si tu écris :
('*ERROR*' or 'ERR') in test2
le "or" est calculé d'abord, et tu testes en substance « '*ERROR*' in
test2 ».
-- Alain.
Avatar
Olivier Miakinen
Le 26/05/2022 17:26, Dominique a écrit :
if 'ERROR':
print('OK')
OK
même si ERROR n'esst pas défini.

Euh... c'est comme si tu t'étonnais de :
if 32:
print('OK')
OK
... sous prétexte que 32 ne serait pas défini. ;-)
--
Olivier Miakinen
Avatar
Dominique
Le 26/05/2022 Í  17:52, Olivier Miakinen a écrit :
Euh... c'est comme si tu t'étonnais de :
if 32:
print('OK')
OK
... sous prétexte que 32 ne serait pas défini. ;-)

Tu as raison :-)
Je suis toujours de l'ancienne école (Sharp PC1211, Amstrad CPC 464,
GWBasic de Microsoft...) o͹ on ne pouvait traiter que des variables, pas
des valeurs absolues.
Par exemple : if 32: quelque chose aurait nécessairement retourné un
message d'erreur.
Merci pour tes explications claires.
Dominique