Pod maską Python użyje __contains__(self, item), __iter__(self)iw __getitem__(self, key)tej kolejności, aby ustalić, czy element leży w danym zawiera. Zaimplementuj co najmniej jedną z tych metod, aby inudostępnić niestandardowy typ.
BallpointBen,
27
Tylko upewnij się, że coś nie będzie Żaden. W przeciwnym razie dostanieszTypeError: argument of type 'NoneType' is not iterable
Big Pumpkin
5
FWIW, to idiomatyczny sposób na osiągnięcie tego celu.
Trenton
6
Czy w przypadku łańcuchów inoperator Python używa algorytmu Rabin-Carp?
Sam Chats,
3
@SamChats patrz stackoverflow.com/questions/18139660/ ... szczegóły implementacji (w CPython; afaik specyfikacja języka nie wymaga tutaj żadnego konkretnego algorytmu).
Christoph Burschka
667
Jeśli jest to tylko wyszukiwanie podciągów, możesz użyć string.find("substring").
Trzeba być trochę ostrożny z find, indexi inchoć są one podciąg wyszukiwania. Innymi słowy, to:
s ="This be a string"if s.find("is")==-1:print("No 'is' here!")else:print("Found 'is' in the string.")
Wypisałby się Found 'is' in the string.podobnie, if "is" in s:oceniałby True. To może być lub nie być to, czego chcesz.
+1 za wyróżnienie błędów związanych z wyszukiwaniem podciągów. oczywistym rozwiązaniem jest to, if ' is ' in s:co powróci, Falsejak się spodziewano (prawdopodobnie).
aaronasterling
94
@aaronasterling Oczywiście może być, ale nie do końca poprawny. Co zrobić, jeśli masz interpunkcję lub jest ona na początku lub na końcu? Co z dużymi literami? Lepszym byłoby wyszukiwanie wyrażeń regularnych bez rozróżniania wielkości liter \bis\b(granice słów).
Bob
2
@JamieBull Jeszcze raz musisz rozważyć, czy chcesz wstawić interpunkcję jako separator słowa. Podział miałby w dużej mierze taki sam efekt, jak naiwne rozwiązanie sprawdzania ' is ', w szczególności, że nie zostanie on złapany This is, a comma'lub 'It is.'.
Bob
7
@JamieBull: Wątpię, czy jakikolwiek prawdziwy podział danych wejściowych podzieliłby się s.split(string.punctuation + string.whitespace)choć raz; splitnie jest jak rodzina funkcji strip/ rstrip/ lstrip, dzieli się tylko wtedy, gdy widzi wszystkie znaki separatora, w sposób ciągły, w dokładnie takiej kolejności. Jeśli chcesz podzielić na klasy znaków, wrócisz do wyrażeń regularnych (w tym momencie wyszukiwanie r'\bis\b'bez podziału jest łatwiejszą i szybszą drogą).
ShadowRanger
8
'is' not in (w.lower() for w in s.translate(string.maketrans(' ' * len(string.punctuation + string.whitespace), string.punctuation + string.whitespace)).split()- ok, punkt wzięty. To jest teraz śmieszne ...
Jamie Bull
190
Czy Python ma ciąg zawierający metodę podciągów?
Tak, ale Python ma operator porównania, którego należy użyć zamiast tego, ponieważ język zamierza go używać, a inni programiści oczekują, że będziesz go używać. To słowo kluczowe jest inużywane jako operator porównania:
>>>'foo'in'**foo**'True
Przeciwnie (uzupełnienie), o które prosi pierwotne pytanie, jest not in:
>>>'foo'notin'**foo**'# returns FalseFalse
Jest to semantycznie to samo, not 'foo' in '**foo**'ale o wiele bardziej czytelne i wyraźnie przewidziane w języku jako poprawa czytelności.
Unikaj używania __contains__, findorazindex
Zgodnie z obietnicą, oto containsmetoda:
str.__contains__('**foo**','foo')
zwraca True. Możesz także wywołać tę funkcję z instancji superstringu:
'**foo**'.__contains__('foo')
Ale nie rób tego. Metody rozpoczynające się od podkreślenia są uważane za semantycznie prywatne. Jedynym powodem, dla którego można to wykorzystać, jest rozszerzenie funkcji ini not in(np. W przypadku podklasy str):
classNoisyString(str):def __contains__(self, other):print('testing if "{0}" in "{1}"'.format(other, self))return super(NoisyString, self).__contains__(other)
ns =NoisyString('a string with a substring inside')
i teraz:
>>>'substring'in ns
testing if"substring"in"a string with a substring inside"True
Unikaj również następujących metod ciągu:
>>>'**foo**'.index('foo')2>>>'**foo**'.find('foo')2>>>'**oo**'.find('foo')-1>>>'**oo**'.index('foo')Traceback(most recent call last):File"<pyshell#40>", line 1,in<module>'**oo**'.index('foo')ValueError: substring not found
Inne języki mogą nie mieć żadnych metod bezpośredniego testowania podciągów, więc musisz użyć tego rodzaju metod, ale w Pythonie znacznie bardziej wydajne jest użycie inoperatora porównania.
Porównanie wydajności
Możemy porównać różne sposoby osiągnięcia tego samego celu.
Dlaczego należy unikać str.indexi str.find? Jak inaczej zasugerowałbyś komuś znalezienie indeksu podciągów zamiast tego, czy istnieje? (czy miałeś na myśli unikanie ich zamiast zawiera - więc nie używaj s.find(ss) != -1zamiast ss in s?)
coderforlife
3
Dokładnie tak, chociaż zamiar zastosowania tych metod można lepiej rozwiązać poprzez eleganckie użycie remodułu. Nie znalazłem jeszcze zastosowania dla str.index lub str.find siebie w żadnym kodzie, który napisałem.
Aaron Hall
Rozszerz swoją odpowiedź na odradzanie używania str.countrównież ( string.count(something) != 0). Dreszcz
if needle in haystack:jest normalnym zastosowaniem, jak mówi @Michael - zależy od inoperatora, jest bardziej czytelny i szybszy niż wywołanie metody.
Jeśli naprawdę potrzebujesz metody zamiast operatora (np. Aby zrobić coś dziwnego key=dla bardzo osobliwego rodzaju ...?), Byłoby to możliwe 'haystack'.__contains__. Ale ponieważ twój przykład jest przeznaczony do użycia if, myślę, że tak naprawdę nie masz na myśli tego, co mówisz ;-). Nie jest dobrą formą (ani czytelną, ani wydajną) używanie specjalnych metod bezpośrednio - są one przeznaczone do użycia przez operatorów i wbudowane w nie funkcje, które je delegują.
Oto kilka przydatnych przykładów, które mówią same za siebie w odniesieniu do inmetody:
"foo"in"foobar"True"foo"in"Foobar"False"foo"in"Foobar".lower()True"foo".capitalize()in"Foobar"True"foo"in["bar","foo","foobar"]True"foo"in["fo","o","foobar"]False["foo"in a for a in["fo","o","foobar"]][False,False,True]
Zastrzeżenie Listy są iterowalne, a inmetoda działa na iterowalne, a nie tylko na ciągi znaków.
Czy iterowalną listę można przełączyć, aby wyszukać dowolną listę w jednym ciągu? Ex: ["bar", "foo", "foobar"] in "foof"?
CaffeinatedCoder,
1
@CaffeinatedCoder, nie, wymaga to zagnieżdżonej iteracji. Najlepiej zrobić to, łącząc listę z potokami „|” .join ([„bar”, „foo”, „foobar”]) i kompilując z niej wyrażenie regularne, a następnie dopasowując „foof”
firelynx
2
dowolna ([x w „foof” dla x w [„bar”, „foo”, „foobar”]])
Izaak Weiss
1
@IzaakWeiss Twój jeden liner działa, ale nie jest zbyt czytelny i zagnieżdża iterację.
Odradzałbym
1
@ PiyushS. Czy rozumiesz, co rozumiesz przez złożoność? „WTF / min” jest znacznie wyższy w przypadku wyrażenia regularnego.
firelynx,
42
Jeśli jesteś zadowolony, "blah" in somestringale chcesz, aby było to wywołanie funkcji / metody, prawdopodobnie możesz to zrobić
Jest tak, ponieważ istnieją bajillionowe sposoby tworzenia produktu ze zmiennych atomowych. Możesz upchnąć je w krotkę, listę (które są formami produktów kartezjańskich i są dostarczane z dorozumianą kolejnością), lub można je nazwać właściwościami klasy (bez zamówienia a priori) lub wartościami słownikowymi, lub mogą być plikami katalog lub cokolwiek innego. Ilekroć możesz jednoznacznie zidentyfikować (iterować lub uzyskać) coś w „kontenerze” lub „kontekście”, możesz zobaczyć ten „kontener” jako rodzaj wektora i zdefiniować na nim operacje binarne. en.wikipedia.org/wiki/…
Niriel,
Nie warto nic, inczego nie należy używać z listami, ponieważ wykonuje liniowy skan elementów i jest powolny w porównaniu. Zamiast tego użyj zestawu, szczególnie jeśli testy członkostwa mają być powtarzane.
cs95
22
Możesz użyć y.count().
Zwraca wartość całkowitą liczby przypadków, gdy podciąć pojawia się w ciągu.
następnie Jeśli masz uprawnienia do usunięcia go, usuń go, w przeciwnym razie zrób to, co musisz, i przejdź dalej. IMO ta odpowiedź dodaje wartości, co znajduje odzwierciedlenie w głosowaniu użytkowników.
__contains__(self, item)
,__iter__(self)
iw__getitem__(self, key)
tej kolejności, aby ustalić, czy element leży w danym zawiera. Zaimplementuj co najmniej jedną z tych metod, abyin
udostępnić niestandardowy typ.TypeError: argument of type 'NoneType' is not iterable
in
operator Python używa algorytmu Rabin-Carp?Jeśli jest to tylko wyszukiwanie podciągów, możesz użyć
string.find("substring")
.Trzeba być trochę ostrożny z
find
,index
iin
choć są one podciąg wyszukiwania. Innymi słowy, to:Wypisałby się
Found 'is' in the string.
podobnie,if "is" in s:
oceniałbyTrue
. To może być lub nie być to, czego chcesz.źródło
if ' is ' in s:
co powróci,False
jak się spodziewano (prawdopodobnie).\bis\b
(granice słów).' is '
, w szczególności, że nie zostanie on złapanyThis is, a comma'
lub'It is.'
.s.split(string.punctuation + string.whitespace)
choć raz;split
nie jest jak rodzina funkcjistrip
/rstrip
/lstrip
, dzieli się tylko wtedy, gdy widzi wszystkie znaki separatora, w sposób ciągły, w dokładnie takiej kolejności. Jeśli chcesz podzielić na klasy znaków, wrócisz do wyrażeń regularnych (w tym momencie wyszukiwanier'\bis\b'
bez podziału jest łatwiejszą i szybszą drogą).'is' not in (w.lower() for w in s.translate(string.maketrans(' ' * len(string.punctuation + string.whitespace), string.punctuation + string.whitespace)).split()
- ok, punkt wzięty. To jest teraz śmieszne ...Tak, ale Python ma operator porównania, którego należy użyć zamiast tego, ponieważ język zamierza go używać, a inni programiści oczekują, że będziesz go używać. To słowo kluczowe jest
in
używane jako operator porównania:Przeciwnie (uzupełnienie), o które prosi pierwotne pytanie, jest
not in
:Jest to semantycznie to samo,
not 'foo' in '**foo**'
ale o wiele bardziej czytelne i wyraźnie przewidziane w języku jako poprawa czytelności.Unikaj używania
__contains__
,find
orazindex
Zgodnie z obietnicą, oto
contains
metoda:zwraca
True
. Możesz także wywołać tę funkcję z instancji superstringu:Ale nie rób tego. Metody rozpoczynające się od podkreślenia są uważane za semantycznie prywatne. Jedynym powodem, dla którego można to wykorzystać, jest rozszerzenie funkcji
in
inot in
(np. W przypadku podklasystr
):i teraz:
Unikaj również następujących metod ciągu:
Inne języki mogą nie mieć żadnych metod bezpośredniego testowania podciągów, więc musisz użyć tego rodzaju metod, ale w Pythonie znacznie bardziej wydajne jest użycie
in
operatora porównania.Porównanie wydajności
Możemy porównać różne sposoby osiągnięcia tego samego celu.
A teraz widzimy, że używanie
in
jest znacznie szybsze niż inne. Im mniej czasu na wykonanie równoważnej operacji, tym lepiej:źródło
str.index
istr.find
? Jak inaczej zasugerowałbyś komuś znalezienie indeksu podciągów zamiast tego, czy istnieje? (czy miałeś na myśli unikanie ich zamiast zawiera - więc nie używajs.find(ss) != -1
zamiastss in s
?)re
modułu. Nie znalazłem jeszcze zastosowania dla str.index lub str.find siebie w żadnym kodzie, który napisałem.str.count
również (string.count(something) != 0
). Dreszczoperator
wersja modułu ?in_
powyżej - ale z ramką stosu, więc jest wolniejszy: github.com/python/cpython/blob/3.7/Lib/operator.py#L153if needle in haystack:
jest normalnym zastosowaniem, jak mówi @Michael - zależy odin
operatora, jest bardziej czytelny i szybszy niż wywołanie metody.Jeśli naprawdę potrzebujesz metody zamiast operatora (np. Aby zrobić coś dziwnego
key=
dla bardzo osobliwego rodzaju ...?), Byłoby to możliwe'haystack'.__contains__
. Ale ponieważ twój przykład jest przeznaczony do użyciaif
, myślę, że tak naprawdę nie masz na myśli tego, co mówisz ;-). Nie jest dobrą formą (ani czytelną, ani wydajną) używanie specjalnych metod bezpośrednio - są one przeznaczone do użycia przez operatorów i wbudowane w nie funkcje, które je delegują.źródło
in
Ciągi i listy w języku PythonOto kilka przydatnych przykładów, które mówią same za siebie w odniesieniu do
in
metody:Zastrzeżenie Listy są iterowalne, a
in
metoda działa na iterowalne, a nie tylko na ciągi znaków.źródło
["bar", "foo", "foobar"] in "foof"
?Jeśli jesteś zadowolony,
"blah" in somestring
ale chcesz, aby było to wywołanie funkcji / metody, prawdopodobnie możesz to zrobićWszystkich operatorów w Pythonie można mniej więcej znaleźć w module operatora, w tym
in
.źródło
Najwyraźniej więc nie ma nic podobnego w porównaniu wektorowym. Oczywistym sposobem na zrobienie tego byłoby:
źródło
in
czego nie należy używać z listami, ponieważ wykonuje liniowy skan elementów i jest powolny w porównaniu. Zamiast tego użyj zestawu, szczególnie jeśli testy członkostwa mają być powtarzane.Możesz użyć
y.count()
.Zwraca wartość całkowitą liczby przypadków, gdy podciąć pojawia się w ciągu.
Na przykład:
źródło
Oto twoja odpowiedź:
Aby sprawdzić, czy jest to fałsz:
LUB:
źródło
Możesz użyć wyrażeń regularnych, aby uzyskać wystąpienia:
źródło