fbpx

Mateusz Mazurek – programista z pasją

Czyli o użyciu Pythona i kilku innych technologii do tworzenia świetnej jakości aplikacji w oparciu o stabilny proces dostarczania oprogramowania.

Programowanie Programowanie webowe

Czego nie powinniśmy robić w Pythonie? #3

Witam w trzecim artykule z serii dotyczącej tego, czego nie powinniśmy robić w Pythonie. Załączam dwa poprzednie wpisy:

i bez przydługiego wstępu, przejdźmy do treści.

Z rozwagą używajmy metody insert z obiektu listy

Metoda insert(index, element) pozwala dodać do listy element na konkretnym miejscu (indeksie). Zerknijmy na kod:

1
2
3
4
5
6
numbers = []

numbers.insert(0, 'jeden')
numbers.insert(len(numbers), 'dwa')

print(numbers)

Ponieważ najpierw dodaliśmy do listy na indeksie zerowym słowo „jeden”, a potem na indeksie równym długości listy (a więc tu na pierwszym) słowo „dwa”, wobec tego uzyskany wynik to:

['jeden', 'dwa']

I to wszystko jest pewnie jasne.

To przed czym chciałbym przestrzec, to sytuacja w której dodajemy metodą insert jakiś element na zerowy indeks, ponieważ Python będzie zmuszony do przesunięcia reszty zawartości tej listy.

1
2
3
4
5
6
numbers = []

numbers.insert(0, 'jeden')
numbers.insert(0, 'dwa')

print(numbers)

wynik wykonania się tego kodu to

['dwa', 'jeden']

Czemu w takim razie nie powinno się używać tej metody do dodawania elementów na początek listy? Bo to jest bardzo nieefektywne rozwiązanie.

Jeśli piszesz swój kod i już wiesz, że będziesz potrzebował dodawać elementy na początek listy, radzę skorzystać z obiektu deque. Wykorzystajmy timeit’a i zmierzmy czas wykonania się bliźniaczych operacji dla listy i dla deque (double-ended queue czyli lista dwukierunkowa):

1
2
3
4
from timeit import timeit

print(timeit('s.appendleft(37)', 'import collections; s = collections.deque()', number=100000))
print(timeit('s.insert(0,37)', 's = []', number=100000))

wykonanie takiego kodu da rezultat:

0.007789244002196938 # dla deque
2.211549069004832 # dla listy

Różnica wynika ze złożoności obliczeniowej obu rozwiązań, a złożoność obliczeniowa ze sposobu implementacji ich w Pythonie. Złożoność obliczeniowa dla list.insert() jest liniowa, a dla deque.appendleft() jest stała, czyli niezależna od ilości elementów.


Czekaj, stop!

Podoba Ci się to co tworzę? Jeśli tak to zapraszam Cię do zapisania się na newsletter:
a w ramach prezentu otrzymasz całkowicie za darmo, dokument PDF „6 (nie zawsze oczywistych) błędów popełnianych podczas nauki programowania” który jest jednym z efektów ponad siedmioletniej pracy oraz obserwacji rozwoju niejednego programisty.Jeśli to Cię interesuje to zapraszam również na swoje social media.

Brak rozpakowywania list

Czasem potrzebujemy przypisać elementy z listy do zmiennych, by móc ich potem używać. Możemy to zrobić tak:

1
2
3
4
5
6
7
some_values = ['jeden', 2, 'three']

first = some_values[0]
second = some_values[1]
third = some_values[2]

print(first, second, third)

co oczywiście – zadziała, ale jest to bardzo mało Pythonowe rozwiązanie. Możesz zrobić to lepiej w taki sposób:

1
2
3
4
5
some_values = ['jeden', 2, 'three']

first, second, third = some_values

print(first, second, third)

Czemu tak? Bo to ładne i przede wszystkim Python’owe rozwiązanie. Wynik obu rozwiązań jest taki sam!

Używanie listy do kolekcji elementów w których będziemy tylko szukać

Najlepiej sytuację o której myślę pokaże kawałek kodu:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Shop:
    STATES = ['open', 'closed', 'temporary_closed', 'nearly_closed']

    def __init__(self, state):
        self.state = state

    def has_valid_state(self):
        return self.state in self.STATES


s = Shop('open')

print(s.has_valid_state())

Klasa sklepu ma swoje możliwe stany i w oparciu o wartość pola zwracamy informację, czy aktualny stan jest poprawny. Na 100% widziałeś podobny kod wiele razy.

To podejście oczywiście spełni swoją funkcję. Jest jednak nieoptymalne.

Jeśli chcemy tworzyć kolekcję, której jedynym zastosowaniem jest sprawdzanie, czy jakiś element w niej istnieje, np jak w klasie wyżej – do zawężenia możliwych stanów elementu, powinniśmy zrezygnować z listy. I użyć zbioru.

I znów, udowodnijmy to korzystając z timeit’a!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from timeit import timeit


setup1 = """
STATES = {"OPEN", "NEARLY_CLOSED", "NEARLY_OPEN", "TEMPORARY_CLOSED", "CLOSED"}
"""


setup2 = """
STATES = ["OPEN", "NEARLY_CLOSED", "NEARLY_OPEN", "TEMPORARY_CLOSED", "CLOSED"]
"""



print("Checking in set with not exists element: ", timeit("'NO_EXISTS' in STATES", setup=setup1, number=100000))
print("Checking in list with not exists element: ", timeit("'NO_EXISTS' in STATES", setup=setup2, number=100000))


print("Checking in set with exists element: ", timeit("'NEARLY_OPEN' in STATES", setup=setup1, number=100000))
print("Checking in list with exists element: ", timeit("'NEARLY_OPEN' in STATES", setup=setup2, number=100000))

i wynik kodu:

Checking in set with not exists element: 0.0025714500006870367
Checking in list with not exists element: 0.006017967999468965
Checking in set with exists element: 0.0023319259998970665
Checking in list with exists element: 0.0035892980004064157

Sprawdzamy tu 4 przypadki:

  • szukanie w zbiorze nie istniejącego elementu
  • szukanie w liście nie istniejącego elementu
  • szukanie w zbiorze istniejącego elementu
  • szukanie w liście istniejącego elementu

I, co widać po czasach, wygrywa zbiór. Zatem polecam używać go w sytuacjach kiedy rozważamy posiadanie kolekcji w której będziemy tylko szukać.

Tym wnioskiem kończymy ten wpis. Będą kolejne :)

Dzięki za wizytę,
Mateusz Mazurek

A może wolisz nowości na mail?

3
Dodaj komentarz

avatar
2 Wątki
1 Odpowiedzi
1 Śledzący
 
Komentarz z największą liczbą reakcji
Najczęściej komentowany wątek
2 Komentarze autora
Mateusz M.Adrian Ostatnie komentarze autora

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.

  Subskrybuj  
Powiadom o
Adrian
Gość

Trochę już w Pythonie programuję, ale dzięki tej serii widzę co mogę robić lepiej :)

trackback

[…] Czego nie powinniśmy robić w Pythonie? […]

Halo, halo, czekaj chwilę, nie zamykaj!

Super się cieszę że tu jesteś! Bloga tego prowadzę już jakiś czas, uwielbiam pisać i dzielić się wiedzą ale moja pasja do tego jest bez sensu jeśli nie mam czytelników :(

W tej chwili chciałbym Cię zaprosić do zapisania się na newsletter i bycia na bieżąco z tym co przygotowuję. W zamiana za okazane zaufanie dostaniesz dostęp do dokumentu PDF

6(nie zawsze oczywistych) błędów popełnianych podczas nauki programowania”

całkowicie ZA DARMO – wiem, szok i niedowierzanie że daje coś za darmo. Ale ja serio lubię się dzielić wiedzą! Zostaw po prostu swój mail tu – link do zapisania się.