10 nietypowych zachowań w Python


Poznaj 10 nietypowych zachowań i błędów jakie można spotkać w języku Python


Nie pamiętam ile razy naśmialiśmy się w JavaScript, że zachowuje sie nieprzewidywalnie i dziwnie. Ale Python również posiada sytuacje w których kod zachowuje sie nie po naszej myśli. Niżej subiektywna lista 10 dziwnych i nietypowych zachowań w Python. Część wynika z błędów programisty a część ze specyfiki języka. Nie będę się zagłębiać i wyjaśniać dlaczego one powstają. Wykonajmy wspólnie pewnie ćwiczenie a przekonacie się, że wyniki mogą Was zaskoczyć ;)

A więc bez zbędnego przedłużania zaczynajmy. Gorąco zachęcam do zapisania rozwiązań na boku.

Atrybuty klasowe

Mamy jedną klasę bazową A i dwie klasy które z niej dziedziczą B i C. Kod przedstawiony jest niżej

class A:
    a = 1

class B(A):
    pass

class C(A):
    pass

Jaki będzie wynik przy edycji atrybutu a ?

B.a = 10
print(A.a, B.a, C.a)
A.a = 20
print(A.a, B.a, C.a)

Wartość domyślna funkcji

Napiszmy prostą funkcję, która doda nowy element na końcu listy i wypisze całą listę.

def ddeby(blog=[]):
    blog.append('Python')
    print(blog)

Jaki będzie zatem wynik?

ddeby()
ddeby()
ddeby()

Scope zmiennych

Napiszmy 3 proste funkcje, które będą operować na zdefiniowanych wcześniej zmiennych. Dla urozmaicenia niech dwie operują na liście a jedna na liczbie całkowitej.

num = 5
data = ['ddeby']

def ddeby():
    data.append('blog')
    print(data)


def blog():
    num += 5
    print(num)


def dawid():
    data += ['Python']

Jaki będzie wynik przy próbie wykonania tych funkcji?

ddeby()
blog() 
dawid()

Metoda __str__

Zapewne każdy wie do czego służy metoda __str__. Sprawdźmy jak zachowa się przy różnych typach danych.

name = 'ddeby'
num = 5

name.__str__()
num.__str__()
'ddeby'.__str__()
5.__str__()

Inicjalizacja funkcji

W modelach danych często wykorzystuje się pole daty. Zdarza się, że zachodzi potrzeba automatycznego uzupełnienia daty. Napiszmy zatem prostą funkcję, która wyświetli aktualną datę.

from datetime import datetime

def get_today(now=datetime.today()):
    return now

Jaki będzie wynik przy próbie zwrócenia tej daty?

get_today()
get_today()
get_today()

Dodawanie liczb rzeczywistych

Zaawansowana matematyka nie jest potrzebna programiście. Jednak takie podstawy jak dodawanie i odejmowanie liczb są raczej proste. Sprawdźmy czy aby na pewno. Jaki będzie wynik poniższych działań?

0.1 + 0.1
0.2 + 0.2
0.1 + 0.2

Definicja tupli

O listach i tuplach pisałem już w innym wpisie. Czy jest jeszcze jakaś różnica, której nie opisałem?

a_list = [1, 2]
b_list = [1]
a_tupe = (1, 2)
b_tuple = (1)

type(a_list)
type(b_list)
type(a_tuple)
type(b_tuple)

Warunek z in

In sprawdza czy dana wartość znajduje się na liście i zwraca wartośc logiczną. Jaki będzie zatem wynik poniższego kodu?

1 in [1]
1 in [1] is True

Operatory logiczne

Zamiast pisać wiele wcięć można sprawdzić wiele warunków za jednym razem. Operatory logiczne mają też inne ciekawe zastosowanie. Jakie wartości zostaną zwrócne w każdej z tych linijek?

False or 'python'
'ddeby' or False
'ddeby' and 'python'
False and 'python'
True and 'python'

Edycja listy

Listy są o tyle ciekawe, że znalazły się tu ponownie. Tym razem zobaczmy jak zachowa się edycja konkretnych elementów na liście. Co zostanie wypisane?

data = ['blog'] * 3
ddeby = [['blog'] * 3] * 3

data[1] = 'python'
ddeby[1][1] = 'python'

print(data)
print(ddeby)

Odpowiedzi

Atrybuty klasowe

Powrót

B.a = 10
print(A.a, B.a, C.a)  # 1 10 1
A.a = 20
print(A.a, B.a, C.a)  # 20 10 20

Wartość domyślna funkcji

Powrót

ddeby()  # ['Python']
ddeby()  # ['Python', 'Python']
ddeby()  # ['Python', 'Python', 'Python']

Scope zmiennych

Powrót

ddeby()  # ['ddeby', 'blog']
blog()  # UnboundLocalError: local variable 'num' referenced before assignment
dawid()  # UnboundLocalError: local variable 'data' referenced before assignment

Metoda __str__

Powrót

name.__str__()  # 'ddeby'
num.__str__()  # 5
'ddeby'.__str__()  # 'ddeby'
5.__str__()  # SyntaxError: invalid syntax

Inicjalizacja funkcji

Powrót

get_today()  # datetime.datetime(2019, 9, 23, 21, 42, 36, 67247)
get_today()  # datetime.datetime(2019, 9, 23, 21, 42, 36, 67247)
get_today()  # datetime.datetime(2019, 9, 23, 21, 42, 36, 67247)

Dodawanie liczb rzeczywistych

Powrót

0.1 + 0.1  # 0.2
0.2 + 0.2  # 0.4
0.1 + 0.2  # 0.30000000000000004

Definicja tupli

Powrót

type(a_list)  # <class 'list'>
type(b_list)  # <class 'list'>
type(a_tuple)  # <class 'tuple'>
type(b_tuple)    # <class 'int'>

Warunek z in

Powrót

1 in [1]  # True
1 in [1] is True  # False

Operatory logiczne

Powrót

False or 'python'  # 'ddeby'
'ddeby' or False  # 'ddeby'
'ddeby' and 'python'  # 'python'
False and 'python'  # False
True and 'python'  # 'python'

Edycja listy

Powrót

print(data)  # ['blog', 'python', 'blog']
print(ddeby)  # [['blog', 'python', 'blog'], ['blog', 'python', 'blog'], ['blog', 'python', 'blog']]

Bonus

Na koniec jeszcze jeden mały bonusik dla wytrwałych ;). Jak myślicie jakiego typu jest False lub True ? Sprawdźmy

type(False) is bool  # True
typ(False) is int  # False

Co zatem zwróci isinstance ?

isinstance(False, bool)  # True
isinstance(False, int)  # True

Podsumowanie

Które zachowania Was zaskoczyły? A może wszystkie rozwiązałeś poprawnie? Jeśli tak, to koniecznie podziel się tym w komentarzu. A może część z tych zagadnień wymaga dokładnego opisania w oddzielnym wpisie? Jeśli coś jest niejasne również wpisujcie to w komentarzach. Podobnie jeśli znacie inne, dziwne przypadki. Jestem bardzo ciekaw ile ciekawostek wspólnie uda nam się odszukać.

Wrz 23, 2019

Najnowsze wpisy

Zobacz wszystkie