2009-04-18 11 views
15

Moje przygody w Pythonie są kontynuowane, a moje ulubione książki znów milczą. Python oferuje wbudowany sposobem sprawdzenia, czy zmienna jest wewnątrz iterowalny obiektu, za pomocą „w” kluczowych:python, słowo kluczowe "a in b", a co z wieloma a-s?

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

Ale czy to możliwe, aby sprawdzić, czy więcej niż jedna pozycja znajduje się na liście (jednego)? Obecnie używam składni poniżej, ale jest to trochę długo:

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

Of regexes oczywiście może pomóc, ale przy użyciu regexes zajmie dużo gadatliwy kodu i nie być tak oczywiste, jako „ in b ". Czy istnieją inne sposoby Python?

Odpowiedz

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() i all() trwa iterable i sprawdza, czy którykolwiek/wszystkie z nich ocenia się prawdziwej wartości. Połącz to z wyrażeń generatora i możesz sprawdzić wiele elementów.

+5

Dodałem linki do dokumentacji, więc S.Lott cię nie docenia;) Jednak z całą powagą zachęcamy do linkowania do dokumentów, mam nadzieję, że nie masz nic przeciwko. –

+0

Wcale nie. Dzięki. –

7

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

0

Nie ma wbudowanej metody składni. Możesz jednak użyć funkcji "dowolne", aby ułatwić sobie pracę, tak jak pokazały się programy @MizardX i @Benjamin Peterson.

1

Jeśli chcesz każdy czek wtedy użyć tego:

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

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

Jeśli chcesz wszystko check out można użyć to:

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

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

EDIT: Nie wiem tym bardziej pythonic any(). Prawdopodobnie lepiej jest użyć tego na pythonie.

EDIT2: Dodano instrukcje przerwania i poprawionowszystkie -.

1

Można również użyć set methods and operators:

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

Myślę, że są łatwiejsze do odczytania niż przy użyciu jednego lub wszystkich, ale trzeba konwertować swoje zbiory w zestawy. Ponieważ zależy Ci na skrzyżowaniu i ograniczeniu, możesz rozważyć ustawienie ich jako zestawów.

+0

Nie działa, jeśli sTxt jest ciągiem znaków. –

+0

Moja odpowiedź wspomina, że ​​te obiekty muszą być zestawami. – allyourcode

6

Jeśli testujesz wiele wierszy dla tych samych słów, szybsze może być kompilowanie ich jako wyrażenie regularne. np:

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" 

Niektóre szybkie terminy pokazuje, że jest to zwykle szybciej niż podejście any(word in theString for word in words). Przetestowałem oba podejścia z różnym tekstem (krótki/długi z/bez dopasowania). Oto wyniki:

  { 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 

Jeśli wydajność nie ma znaczenia, chociaż, podejście any() jest bardziej czytelny.

+0

\ o/Miło jest mieć testy porównawcze z twierdzeniem "może być szybsze do ..."! – dbr

Powiązane problemy