2009-04-18 5 views
15

Mes aventures en Python continuent et mes livres préférés sont à nouveau silencieux. Python offre un moyen de tester si une variable intégrée est à l'intérieur d'un objet itérable, en utilisant le « dans » mot-clé:python, "a in b" mot-clé, que diriez-vous de plusieurs a?

if "a" in "abrakadabra" : 
    print "it is definitely here" 

Mais est-il possible de tester si plus d'un article se trouve dans la liste (une)? Actuellement, je suis en utilisant la syntaxe ci-dessous, mais il est un peu longue:

if "// @in " in sTxt or "// @out " in sTxt or "// @ret " in sTxt or <10 more> 
    print "found." 

Bien sûr regexes peut aider, mais en utilisant des expressions rationnelles va prendre beaucoup de bavard de code et sera pas aussi clair que « un en b ". Y a-t-il d'autres façons Pythonic?

Répondre

45
alternatives = ("// @in ", "// @out ", "// @ret ") 
if any(a in sTxT for a in alternatives): 
    print "found" 

if all(a in sTxT for a in alternatives): 
    print "found all" 

any() et all() prend un itérables et vérifie si tout/tous les évaluer à une valeur réelle. Combinez cela avec des expressions de générateur, et vous pouvez vérifier plusieurs éléments.

+5

J'ai ajouté des liens vers la documentation afin que S.Lott ne vous rétrograde pas;) En toute sincérité, cependant, il est encouragé à lier les docs, j'espère que cela ne vous dérange pas. –

+0

Pas du tout. Merci. –

7

any(snippet in text_body for snippet in ("hi", "foo", "bar", "spam"))

0

Il n'y a pas de manière intégrée dans la syntaxe de le faire. Cependant, vous pouvez utiliser la fonction 'any' pour le rendre plus facile comme l'ont montré @MizardX et @Benjamin Peterson.

1

Si vous voulez tout chèque que vous utiliserez alors ceci:

inthere = False 
checks = ('a', 'b') 

for check in checks: 
    if check in 'abrakadabra': 
     inthere = True 
     break 

Si vous voulez tous départ, vous pouvez utiliser ceci:

inthere = True 
checks = ('a', 'b') 

for check in checks: 
    if check not in 'abrakadabra': 
     inthere = False 
     break 

EDIT: Je ne savais pas le plus pythonique any(). C'est probablement mieux d'utiliser ça sur python.

EDIT2: Ajout d'instructions de rupture, et correction du tous -case.

1

Vous pouvez également utiliser set methods and operators:

not alternatives.isdisjoint(sTxt) # for "any" 
(alternatives & sTxt) != set() # Again, the intersection is nonempty 
alternatives <= sTxt # for "all" 

Je pense que ceux-ci sont plus faciles à lire que d'utiliser le tout ou partie, mais doivent convertir vos collections en ensembles. Puisque l'intersection et le confinement sont ce qui vous intéresse, vous pourriez envisager de les créer en premier lieu.

+0

Ne fonctionne pas si sTxt est une chaîne. –

+0

Ma réponse mentionne que ces objets doivent être des ensembles. – allyourcode

6

Si vous testez un grand nombre de lignes pour les mêmes mots, il peut être plus rapide de les compiler en tant qu'expression régulière. par exemple:

import re 
words = ["// @in ", "// @out ", "// @ret "] + ["// @test%s " % i for i in range(10)] 

my_regex = re.compile("|".join(map(re.escape, words))) 

for line in lines_to_search: 
    if my_regex.search(line): print "Found match" 

Certains calendrier rapide montre que cela est généralement plus rapide que l'approche any(word in theString for word in words). J'ai testé les deux approches avec du texte variable (court/long avec/sans correspondance). Voici les résultats:

  { No keywords } | {contain Keywords } 
     short long  short long 
regex : 0.214 27.214  0.147 0.149 
any in : 0.579 81.341  0.295 0.300 

Si la performance n'a pas d'importance cependant, l'approche any() est plus lisible.

+0

\ o/C'est sympa d'avoir des benchmarks avec un "peut-être plus rapide à ..." réclamer! – dbr

Questions connexes