22.09.20205 min

James BriggsAI Consultant

Nietypowe, ale przydatne funkcje Pythona

Poznaj kilka mało znanych, ale bardzo przydatnych funkcji Pythona i zobacz, jak możesz ich poprawnie używać.

Nietypowe, ale przydatne funkcje Pythona

Python zawsze czymś nas zaskoczy — w tym języku jest po prostu zbyt wiele wspaniałych funkcji. Oznacza to na szczęście, że zawsze będzie tam coś do nauki. Z biegiem czasu wyrobiłem sobie nawyk zapisywania każdej nowej funkcji, na jaką się w tym języku natknąłem. Są one dość interesujące, ale nie można ich używać w wielu przypadkach. Czasami jednak spotykam się z jakąś nietypową funkcją, która ma naprawdę szerokie zastosowanie — i często zmienia ona sposób, w jaki koduję. Stworzyłem sobie listę takich funkcji, a w tym artykule omówię pięć moich ulubionych, które się tam znajdują.

Get Method for Dictionaries - no more KeyErrors
Tree Datatypes - or autovivification
Advanced List Indexing - [::3]?
Decorator Functions - those @ things
Denote Scopes with Braces - not whitespace (my favorite feature)



Metoda Get dla słowników

Metoda słownikowa get wykonuje tę samą operację, co bardziej powszechna składnia dict[key] z jedną jednak różnicą — nie zgłaszamy tu błędu, jeśli key nie istnieje w naszym słowniku:

dictionary = {
    'one': 1,
    'two': 2
}
dictionary['three']
[Out]: KeyError: 'three'


Razem z get —

dictionary.get('three')
[Out]: None


Zamiast zwrócić KeyError, metoda get zwraca None. Możemy pójść o krok dalej, określając wartość do zwrócenia, jeśli key nie istnieje z drugim argumentem metody get:

dictionary.get('three', False)
[Out]: False
dictionary.get('three', "doesn't exist")
[Out]: 'doesn't exist'


Na koniec: jeśli znasz zawartość swojego słownika, to nie używaj get, ponieważ jest to wolniejsze (dzięki Petru).


Typy danych drzewa

Typ danych drzewa wygląda następująco:


Reprezentacja słów w zdaniu i odpowiadających im części mowy w drzewie. 


Powyższy rysunek reprezentuje hierarchiczną strukturę drzewa z wartością główną na najwyższej warstwie, która rozgałęzia się w dół do węzłów potomnych. Każdy węzeł potomny ma jeden węzeł nadrzędny, a każdy węzeł nadrzędny może mieć jeden lub więcej węzłów potomnych. Nasza reprezentacja w Pythonie będzie bardzo podobna do zagnieżdżonego słownika, który zbudujemy w następujący sposób:

tree = {
    'carnivora': {
        'canis': {
            'c.lupus': 'c.l.familiaris'
        },
        'felis': 'f.catus'
    }
}


Musimy tutaj zdefiniować nowy słownik dla każdego węzła potomnego, krok po kroku. Jest to powolny, nieuporządkowany i podatny na błędy proces — wyobraź sobie to dla prostego pięciowarstwowego drzewa, w którym każdy węzeł nadrzędny ma tylko dwa węzły potomne. Możemy zbudować nasz typ danych drzewa w następujący sposób:

class Tree(dict):
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value


Zamiast definiować teraz każdy słownik podrzędny, możemy natychmiast budować całe gałęzie:

tree = Tree()
tree['carnivora']['canis']['c.lupus'] = 'c.l.familiaris'
tree['carnivora']['felis'] = 'f.catus'
print(tree)
[Out]: {
           'carnivora': {
               'canis': {
                   'c.lupus': 'c.l.familiaris'
               },
               'felis': 'f.catus'
           }
       }



Naukowe drzewo klasyfikacyjne przedstawiające najlepszego przyjaciela człowieka i to drugie zwierzę. Zdjęcie: Jamie Street, Unsplash (po lewej) oraz Kari Shea, Unsplash (po prawej).


Metoda ta ma swoją nazwę w języku angielskim — autovivification. Można to określić jako tworzenie nowych tablic mieszających, za każdym razem, gdy spotykamy dereferencję niezdefiniowanej wartości. Kolejną implementację w jednej linijce (z wyłączeniem importu) można znaleźć tutaj.


Zaawansowane indeksowanie list


Kroki

Istnieje kilka nieznanych metod tworzenia wycinków list, pomimo że są one przydatne. Pierwszą z nich są kroki:

x = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
x[::2]
[Out]: [0, 4, 8, 12, 16]


Składnia, której tutaj używamy, to list[start: end: step] — ponieważ pozostawiamy początek i koniec puste i iterujemy od samego początku do końca listy, co drugi element.

x[3:8:2]
[Out]: [6, 10, 14]



Named Slices

Poniższa metoda dzielenia listy nosi nazwę named slices. Przypisujemy tutaj wycinek do zmiennej. Na przykład:

named_slice = slice(5, None)  # this is equivalent to [5:]


Możemy następnie zastosować nasz nazwany wycinek w dowolnej liście.

x[named_slice]
[Out]: [10, 12, 14, 16, 18]


Składnia, której tutaj używamy, używa tego samego wzorca z określeniem początku, końca, kroku — slice(start, end, step). Możemy przepisać x[3:8:2] w następujący sposób:

new_slice = slice(3, 8, 2)
x[new_slice]
[Out]: [6, 10, 14, 18]



Dekoratory

Dekoratory to jedna z tych dziwnych rzeczy typu @func_name, które wielu z nas z pewnością gdzieś widziało. Flash bardzo często je wykorzystuje. Są one zaskakująco łatwe do zrozumienia i niezwykle przydatne. Dekoratory pozwalają nam modyfikować zachowanie naszej funkcji bez potrzeby modyfikowania jej.

Możemy, na przykład, zdefiniować funkcję pointless, która będzie iterować po zakresie liczb, zwracając ostatecznie drukowanie końcowej wartości pomnożonej przez 2:

def pointless():
    for i in range(20000000):
        x = i*2
    print(x)
[Out]: 39999998


Funkcja ta będzie się uruchamiać przez dłuższy czas, ale tego właśnie chcemy. Będziemy mierzyć czas jej działania za pomocą dekoratora. Dekorator jest definiowany, jak każda normalna funkcja:

def timer(func):
    def wrapper():
        start = datetime.datetime.now()
        func()
        runtime = datetime.datetime.now() - start
        print(runtime)
    return wrapper


Możemy następnie użyć @syntax podczas definiowania funkcji do dziedziczenia zachowania timera.

@timer
def pointless():
    for i in range(20000000):
        x = i*2
    print(x)
pointless()
[Out]: 39999998
       0:00:01.220755  <-- this is returned from our decorator


Możemy również użyć wielu dekoratorów. Zdefiniujmy jeden i nazwizjmy go repeat. Będzie on dwukrotnie iterował po dowolnej funkcji.

def repeat(func):
    def wrapper():
        for i in range(2):
            func()
            print(i)
    return wrapper


Jeśli zastosujemy teraz dekoratory @timer oraz @repeat do funkcji pointless, oto, co otrzymamy:

@timer
@repeat
def pointless():
    for i in range(20000000):
        x = i*2
    print(x)
pointless()
[Out]: 39999998
       0               <-- printed in @repeat
       39999998
       1               <-- @repeat again
       0:00:01.220755  <-- printed from @timer


Opakowaliśmy tutaj pointless w @repeat, a wynikową funkcję w @timer. Wygląda to całkiem potwornie. Dekoratory, których tutaj użyliśmy, to tylko „zabawki”. Możemy z nimi zrobić dużo więcej — polecam zapoznać się z następującymi artykułami:


Oznaczanie zasięgów nawiasami klamrowymi

Jest to moja ulubiona zaawansowana funkcja w Pythonie. Zamiast polegać na wcięciach przy oznaczaniu zasięgów, możemy użyć nawiasów klamrowych. Importujemy funkcję z biblioteki __future__:

from __future__ import braces


I ruszamy!

No i tyle! Oto top pięć nietypowych, ale bardzo przydatnych funkcji w Pythonie. Poniżej wyróżnienia:

>>> import this
>>> import antigravity
>>> hash(float('inf'))


Przygotowałem małe repozytorium na GitHubie z przykładami wszystkich powyższych funkcji i nie tylko. Sprawdź, czy znajdziesz tam powyższe fragmenty kodu. Oczywiście możesz też dodać własne.

Jeśli masz jakieś sugestie albo pytania, skontaktuj się ze mną za pośrednictwem Twittera.

Dziękuję za uwagę!


Oryginał tekstu w języku angielskim przeczytasz tutaj.

<p>Loading...</p>

Powiązane artykuły

Dziel się wiedzą ze 160 tysiącami naszych czytelników

Zostań autorem Readme

Affirm

Software Engineer (Python)

medium

13 600 - 16 100 PLN

Umowa o pracę

Warszawa

Praca zdalna 100%

Ważna do 26.02.2022

Dobrze
PythonReact
Początkująco
AWSKubernetesSpark

Beekeeper

IT Support Engineer (SaaS)

medium

Znamy widełki

Umowa o pracę

Kraków

Ważna do 26.02.2022

Dobrze
PythonGoApple

Sofomo

Python Senior Developer

senior

12 000 - 20 000 PLN

Kontrakt B2B

Wrocław

Praca zdalna 100%

Ważna do 12.03.2022

Bardzo dobrze
PythonDjango
Początkująco
AWSReactMicroservices
Dobrze
Docker

Nokia

Python/C++ Engineer

medium

Brak widełek

Umowa o pracę

Kraków

Praca zdalna 100%

Ważna do 12.03.2022

Bardzo dobrze
C++/Python

Affirm

Staff Backend Developer

senior

23 900 - 28 700 PLN

Umowa o pracę

Warszawa

Praca zdalna 100%

Ważna do 24.02.2022

Bardzo dobrze
Python
Dobrze
AWSSparkReact

Affirm

Staff Backend Software Engineer

senior

23 900 - 28 700 PLN

Umowa o pracę

Warszawa

Praca zdalna 100%

Ważna do 24.02.2022

Bardzo dobrze
Python
Dobrze
JavaGoKotlin

Affirm

Software Engineer (Backend)

medium

13 600 - 16 100 PLN

Umowa o pracę

Warszawa

Praca zdalna 100%

Ważna do 24.02.2022

Bardzo dobrze
Python
Dobrze
FlaskSwaggerAmazon S3

Accenture Polska

Big Data Developer (praca zdalna)

medium

15 000 - 23 000 PLN

Kontrakt B2BUmowa o pracę

Praca zdalna 100%

Ważna do 23.02.2022

Bardzo dobrze
PythonSQL
Dobrze
LinuxScalaSpark
Początkująco
GCPHive

Sii Polska

Junior Python Automation Tester

junior

Brak widełek

Kontrakt B2BUmowa o pracę

Praca zdalna 100%

Ważna do 23.02.2022

Początkująco
Python

ONWELO SA

Python Developer

medium

10 500 - 18 900 PLN

Kontrakt B2BUmowa o pracę

Praca zdalna 100%

Ważna do 23.02.2022

Dobrze
PythonDjango/FlaskPytest
Początkująco
DockerKubernetesAWS/GCP/Azure