Zanurkuj w Pythonie/Filtrowanie listy

Filtrowanie listy

edytuj

Jak już wiemy, Python ma potężne możliwości odwzorowania list w inne listy poprzez wyrażenia listowe (rozdział "Odwzorowywanie listy"). Wyrażenia listowe możemy też łączyć z mechanizmem filtrowania, dzięki któremu pewne elementy listy są odwzorowywane a pewne pomijane.

Poniżej przedstawiono składnię filtrowania listy:

[wyrażenie odwzorowujące for element in odwzorowywana lista if wyrażenie filtrujące]

Jest to wyrażenie listowe z pewnym rozszerzeniem. Początek wyrażenia jest identyczny, ale końcowa część zaczynająca się od if, jest wyrażeniem filtrującym. Wyrażenie filtrujące może być dowolnym wyrażeniem, które może zostać zinterpretowane jako wyrażenie logiczne. Każdy element dla którego wyrażenie to będzie prawdziwe, zostanie dołączony do wyjściowej listy. Wszystkie inne elementy dla których wyrażenie filtrujące jest fałszywe, zostaną pominięte i nie trafią do wyjściowej listy.

Przykład. Filtrowanie listy
>>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]
>>> [elem for elem in li if len(elem) > 1]        #(1)
['mpilgrim', 'foo']
>>> [elem for elem in li if elem != "b"]          #(2)
['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
>>> [elem for elem in li if li.count(elem) == 1]  #(3)
['a', 'mpilgrim', 'foo', 'c']

  1. W tym przykładzie wyrażenie odwzorowujące nie jest skomplikowane (zwraca po prostu wartość każdego elementu), więc skoncentrujmy się na wyrażeniu filtrującym. Kiedy Python przechodzi przez każdy element listy, sprawdza czy wyrażenie filtrujące jest prawdziwe dla tego elementu. Jeśli tak będzie, to Python wykona wyrażenie odwzorowujące na tym elemencie i wstawi odwzorowany element do zwracanej listy. W tym przypadku odfiltrowujemy wszystkie łańcuchy znaków, które mają więcej niż jeden znak, tak więc otrzymujemy listę wszystkich dłuższych napisów.
  2. Tutaj odfiltrowujemy elementy, które przechowują wartość "b". Zauważmy, że to wyrażenie listowe odfiltrowuje wszystkie wystąpienia "b", ponieważ za każdym razem, gdy dany element będzie równy "b", wyrażenie filtrujące będzie fałszywe, a zatem wartość ta nie zostanie wstawiona do zwracanej listy.
  3. count jest metodą listy, która zwraca ilość wystąpień danej wartości w liście. Można się domyślać, że ten filtr usunie duplikujące się wartości, przez co zostanie zwrócona lista, która zawiera tylko jedną kopię każdej wartości z oryginalnej listy. Jednak tak się nie stanie. Wartości, które pojawiają się dwukrotnie w oryginalnej liście (w tym wypadku "b" i "d") zostaną całkowicie odrzucone. Istnieje możliwość usunięcia duplikatów z listy, jednak filtrowanie listy nie daje nam takiej możliwości.

Wróćmy teraz do apihelper.py, do poniższej linii:

    methodList = [method for method in dir(object) if callable(getattr(object, method))]

To wyrażenie listowe wygląda skomplikowanie, a nawet jest skomplikowane, jednak podstawowa struktura jest taka sama. Całe to wyrażenie zwraca listę, która zostaje przypisana do zmiennej methodList. Pierwsza część to część odwzorowująca listę. Wyrażenie odwzorowujące zwraca wartość danego elementu. dir(object) zwraca listę atrybutów i metod obiektu object, czyli jest to po prostu lista, którą odwzorowujemy. Tak więc nową częścią jest tylko wyrażenie filtrujące znajdujące się za instrukcją if.

To wyrażenie nie jest takie straszne, na jakie wygląda. Już poznaliśmy funkcje callable, getattr oraz in. Jak już wiemy z poprzedniego podrozdziału, funkcja getattr(object, method) zwraca obiekt funkcji (czyli referencję do tej funkcji), jeśli object jest modułem, a method jest nazwą funkcji w tym module.

Podsumowując, wyrażenie bierze pewien obiekt (nazwany object). Następnie pobiera listę nazw atrybutów tego obiektu, a także metod i funkcji oraz kilka innych rzeczy. Następnie odrzuca te rzeczy, które nas nie interesują, czyli pobieramy nazwy każdego atrybutu/metody/funkcji, a następnie za pomocą getattr pobieramy referencje do atrybutów o tych nazwach. Potem za pomocą funkcji callable sprawdzamy, czy ten obiekt jest wywoływalny, a dzięki temu dowiadujemy się, czy mamy do czynienia z metodą lub jakąś funkcją. Mogą to być na przykład funkcje wbudowane (np. metoda listy o nazwie pop), czy też funkcje zdefiniowane przez użytkownika (np. funkcja buildConnectionString z modułu odbchelper). Nie musimy natomiast martwić się o inne atrybuty jak np. wbudowany do każdego modułu atrybut __name__ (nie jest on wywoływalny, czyli callable zwróci wartość False).

Materiały dodatkowe

edytuj

Python Tutorial omawia inny sposób filtrowania listy, za pomocą wbudowanej funkcji filter.