Naucz się Pythona od zera

Po pierwsze, czym w ogóle jest Python? Według jego twórcy, Guido van Rossuma, Python to:
„Język programowania wysokiego poziomu, a jego podstawową filozofią jest czytelność kodu i składni, która pozwala programistom na wyrażanie pojęć w kilku liniach kodu”.
Dla mnie pierwszym powodem do nauki Pythona był fakt, że jest to piękny język programowania. Kodowanie i wyrażanie myśli w Pythonie przychodziło mi od początku naprawdę naturalne.
Innym powodem było to, że można używać kodowania w Pythonie na wiele sposobów: do nauki o danych, tworzenia stron internetowych i wykorzystania do machine learningu. Wszystko to w jednym. Quora, Pinterest i Spotify używają Pythona na back-endzie. Dowiedzmy się o tym trochę więcej.
Podstawy
Zmienne
Możesz myśleć o zmiennych jako słowach przechowujących wartość. Proste.
W Pythonie bardzo łatwo jest zdefiniować zmienną i ustawić jej wartość. Wyobraź sobie, że chcesz zapisać numer 1 w zmiennej o nazwie „jeden”. Zróbmy to:
one = 1
Czy to może być prostsze? Właśnie przypisałeś wartość 1 do zmiennej „jeden”.
two = 2
some_number = 10000
Możesz przypisać dowolną inną wartość do dowolnej innej zmiennej. Jak widać w powyższej tabeli, zmienna „two” przechowuje liczbę całkowitą 2, a some_number
- 10 000.
Poza liczbami całkowitymi, możemy również użyć booleans (True/False
), stringów
, floatów
i wielu innych typów danych.
# booleans
true_boolean = True
false_boolean = False
# string
my_name = "Leandro Tk"
# float
book_price = 15.80
Control Flow: Instrukcje warunkowe
“If” sprawdza czy wyrażenie ewaluowało się do True czy False. Jeżeli to True, to wykona to, co jest wewnątrz instrukcji “if”. Na przykład:
if True:
print("Hello Python If")
if 2 > 1:
print("2 is greater than 1")
2 jest większe niż 1, więc kod „print” jest wykonywany.
Instrukcja „else” zostanie wykonana, jeśli wyrażenie „if” jest fałszywe.
if 1 > 2:
print("1 is greater than 2")
else:
print("1 is not greater than 2")
1 nie jest większe niż 2, więc kod wewnątrz instrukcji „else” zostanie wykonany.
Możesz także użyć „elif”:
if 1 > 2:
print("1 is greater than 2")
elif 2 > 1:
print("1 is not greater than 2")
else:
print("1 is equal to 2")
Pętla / Iterator
W Pythonie możemy iterować w różny sposób. Powiem o dwóch: ‘while’ i ‘for’.
Pętla ‘while’: gdy instrukcja jest prawdziwa, kod wewnątrz bloku zostanie wykonany. Kod ten wywoła liczbę od 1 do 10.
num = 1
while num <= 10:
print(num)
num += 1
Pętla ‘while’ wymaga „warunku pętli”. Jeśli pozostanie ona prawdziwa, iteracja będzie kontynuowana. W tym przykładzie, gdy num
wynosi 11
, “warunek pętli” jest równy False
.
Kolejny podstawowy fragment kodu, aby to lepiej zrozumieć:
loop_condition = True
while loop_condition:
print("Loop Condition keeps: %s" %(loop_condition))
loop_condition = False
“Warunek pętli” daje True
, więc kontynuuje iterację - dopóki nie osiągnie False
.
Dla zapętlenia: stosuje się zmienną ‘num’ do bloku, a instrukcja ‘for’ iteruje za Ciebie. Ten kod zostanie wykonany tak samo, jak ‘while’: od 1 do 10.
for i in range(1, 11):
print(i)
Widzisz? To naprawdę proste. Zakres zaczyna się od 1
. i idzie do 11
. elementu (10
to 10
-ty element).
Lista: Kolekcja, Tablica, Struktura danych
Wyobraź sobie, że chcesz zapisać liczbę całkowitą 1 w zmiennej. Ale może teraz chcesz zapisać 2. Oraz 3, 4, 5…
Czy jest inny sposób przechowywania wszystkich liczb całkowitych, które chcę, ale nie w milionach zmiennych? Oczywiście, że tak.Lista
to kolekcja, która może być używana do przechowywania wartości (takich, jak te liczby całkowite, które chcesz mieć). Wykorzystajmy to:
my_integers = [1, 2, 3, 4, 5]
To jest naprawdę proste. Stworzyliśmy tablicę i zapisaliśmy ją w ‘my_integer’. Ale zpytasz: „Jak mogę pozyskać wartość z tej tablicy?” Świetne pytanie. Lista
ma koncept zwany indeksem. Pierwszy element otrzymuje indeks 0 (‘zero’). Drugi dostaje 1 i tak dalej.
A trochę jaśniej - możemy reprezentować tablicę i każdy element wraz z jej indeksem. Narysuję to:
Używając składni Pythona, również łatwo jest też zrozumieć:
my_integers = [5, 7, 1, 3, 4]
print(my_integers[0]) # 5
print(my_integers[1]) # 7
print(my_integers[4]) # 4
A teraz wyobraź sobie, że nie chcesz przechowywać liczb całkowitych. Chcesz po prostu przechowywać ciągi znaków, jak lista nazwisk Twoich krewnych. Mój wyglądałby mniej więcej tak:
relatives_names = [
"Toshiaki",
"Juliana",
"Yuji",
"Bruno",
"Kaio"
]
print(relatives_names[4]) # Kaio
Działa tak samo jak liczby całkowite. Super.
Właśnie dowiedzieliśmy się, jak działają indeksy w list
. Ale wciąż muszę Ci pokazać, jak możemy dodać element do struktury danych Listy
. Najpopularniejszą metodą dodawania nowej wartości do listy
jest jej dołączanie (append
). Zobaczmy, jak to działa:
bookshelf = []
bookshelf.append("The Effective Engineer")
bookshelf.append("The 4 Hour Work Week")
print(bookshelf[0]) # The Effective Engineer
print(bookshelf[1]) # The 4 Hour Work Week
Używanie append
jest bardzo proste. Wystarczy zastosować element (np. „The Effective Engineer”) jako parametr append
.
Cóż, wystarczy już o listach. Porozmawiajmy o innej strukturze danych.
Struktura danych klucz-wartość
Teraz wiemy, że listy są indeksowane liczbami całkowitymi. A co, jeśli nie chcemy używać liczb całkowitych jako indeksów? Niektóre struktury danych, których możemy użyć, numeryczne, są ciągami znaków lub innymi typami indeksów.
Nauczmy się, czym jest słownik struktury danych. To kolekcja połączeń klucz-wartość. Tak to wygląda:
dictionary_example = {
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
Klucz jest indeksem wskazującym wartość. Jak uzyskamy dostęp do wartości Dictionary
? Używając klucza.
dictionary_tk = {
"name": "Leandro",
"nickname": "Tk",
"nationality": "Brazilian"
}
print("My name is %s" %(dictionary_tk["name"])) # My name is Leandro
print("But you can call me %s" %(dictionary_tk["nickname"])) # But you can call me Tk
print("And by the way I'm %s" %(dictionary_tk["nationality"])) # And by the way I'm Brazilian
Stworzyłem Dictionary
o mnie. Z moim imieniem, pseudonimem i narodowością. Te atrybuty to klucze słownika.
Jeśli dowiedzieliśmy się, jak uzyskać dostęp do Listy za pomocą indeksu, użyjmy również indeksów (w kontekście słownika), aby uzyskać dostęp do wartości przechowywanej w Dictionary
. W przykładzie wywołałem frazę o mnie, używając wszystkich wartości zapisanych w słowniku.
Kolejną fajną rzeczą w Dictionary
jest to, że możemy wykorzystać wszystko jako wartość. W utworzonym przeze mnie słowniku chcę dodać klucz wiek (‘age’), a w nim mój prawdziwy wiek całkowity:
dictionary_tk = {
"name": "Leandro",
"nickname": "Tk",
"nationality": "Brazilian",
"age": 24
}
print("My name is %s" %(dictionary_tk["name"])) # My name is Leandro
print("But you can call me %s" %(dictionary_tk["nickname"])) # But you can call me Tk
print("And by the way I'm %i and %s" %(dictionary_tk["age"], dictionary_tk["nationality"])) # And by the way I'm Brazilian
Tutaj mamy parę klucz (age) wartości (24) używający stringa jako klucza i liczby całkowitej jako wartości.
Podobnie jak w przypadku list, nauczymy się dodawać elementy do słownika. Klucz wskazujący na wartość stanowi dużą część słownika (Dictionary
). Dotyczy to również sytuacji, gdy mówimy o dodawaniu do niego elementów:
dictionary_tk = {
"name": "Leandro",
"nickname": "Tk",
"nationality": "Brazilian"
}
dictionary_tk['age'] = 24
print(dictionary_tk) # {'nationality': 'Brazilian', 'age': 24, 'nickname': 'Tk', 'name': 'Leandro'}
Musimy tylko przypisać wartość do klucza Dictionary
. Nic skomplikowanego, prawda?
Iteracja: Przechodzenie przez struktury danych w pętli
Iteracja listy jest bardzo prosta. My, programiści Pythona, często używamy for
do pętli. Zróbmy to:
bookshelf = [
"The Effective Engineer",
"The 4 hours work week",
"Zero to One",
"Lean Startup",
"Hooked"
]
for book in bookshelf:
print(book)
Tak więc dla każdej książki na półce z książkami, możemy wykonać dowolną operację, w tym przypadku wypiszemy ją na ekran.
Dla słowników możemy również użyć pętli for
, ale zastosujemy klucz:
dictionary = { "some_key": "some_value" }
for key in dictionary:
print("%s --> %s" %(key, dictionary[key]))
# some_key --> some_value
To jest przykład, jak go używać. Dla każdego klucza w słowniku wypisujemy na ekran klucz i odpowiadającą mu wartość.
Innym sposobem jest użycie metody iteritems
.
dictionary = { "some_key": "some_value" }
for key, value in dictionary.items():
print("%s --> %s" %(key, value))
# some_key --> some_value
Nazwaliśmy dwa parametry jako klucz i wartość, ale nie jest to konieczne. Możemy im nazwać je jakkolwiek. Zobaczmy:
dictionary_tk = {
"name": "Leandro",
"nickname": "Tk",
"nationality": "Brazilian",
"age": 24
}
for attribute, value in dictionary_tk.items():
print("My %s is %s" %(attribute, value))
# My name is Leandro
# My nickname is Tk
# My nationality is Brazilian
# My age is 24
Użyliśmy atrybutu jako parametru dla klucza słownika i działa on poprawnie.
Klasy i obiekty
Obiekty reprezentują rzeczywiste obiekty, takie jak samochody, psy lub rowery. Mają dwie główne cechy: dane i zachowanie. Samochody mają dane, takie jak liczba kół, drzwi i miejsc siedzących. Zachowują się również w taki sposób, że: mogą przyspieszyć, zatrzymać się, pokazać, ile paliwa zostało i wiele innych rzeczy.
Identyfikujemy dane jako atrybuty i zachowanie jako metody programowania obiektowego.
Klasa to plan, z którego tworzone są poszczególne obiekty. W rzeczywistym świecie często znajdujemy wiele obiektów tego samego typu. Jak samochody. Wszystkie marki i modele (wszystkie mają silnik, koła, drzwi itd.). Każdy samochód został zbudowany na podstawie tego samego planu i z tych samych elementów.
Tryb programowania obiektowego w Pythonie: Włączony
Python, jako język programowania obiektowego, posiada następujące pojęcia: klasa i obiekt. Klasa jest szablonem, jest definicją dla obiektów, które na jej podstawie są budowane.
Znowu klasa to tylko model lub sposób na zdefiniowanie atrybutów i zachowania. Na przykład klasa pojazdu ma swoje własne atrybuty, które określają, jakie obiekty są pojazdami. Liczba kół, typ zbiornika, pojemność siedzenia i maksymalna prędkość to wszystkie atrybuty pojazdu. Mając to na uwadze, spójrzmy na składnię Pythona dla klas:
class Vehicle:
pass
Definiujemy klasy za pomocą deklaracji 'class'. To wszystko.
Obiekty są instancjami klasy. Tworzymy instancję, nadając jej nazwę.
car = Vehicle()
print(car) # <__main__.Vehicle instance at 0x7fb1de6c2638>
Tutaj samochód jest obiektem (lub instancją) klasy pojazdu.
Pamiętaj, że klasa pojazdów ma cztery atrybuty: liczbę kół, typ zbiornika, ilość miejsc siedzących i maksymalną prędkość. Wszystkie te atrybuty ustawiamy podczas tworzenia obiektu pojazdu. Dlatego tutaj definiujemy naszą klasę do otrzymywania danych podczas inicjowania:
class Vehicle:
def __init__(self, number_of_wheels, type_of_tank, seating_capacity, maximum_velocity):
self.number_of_wheels = number_of_wheels
self.type_of_tank = type_of_tank
self.seating_capacity = seating_capacity
self.maximum_velocity = maximum_velocity
Używamy metody init
. Nazywamy to metodą konstruktora. Kiedy tworzymy obiekt pojazdu, możemy zdefiniować te atrybuty. Wyobraź sobie, że kochamy model Tesla S i chcemy stworzyć tego rodzaju obiekt. Ma cztery koła, działa na energię elektryczną, ma pięć siedzeń, a maksymalna prędkość wynosi 250 km/h. Utwórzmy ten obiekt:
tesla_model_s = Vehicle(4, 'electric', 5, 250)
Cztery koła + elektryczny „typ zbiornika” + pięć miejsc + maksymalna prędkość 250 km/h.
Wszystkie atrybuty są ustawione. Ale jak możemy uzyskać dostęp do wartości tych atrybutów? Wysyłamy wiadomość do obiektu z pytaniem o nie. Nazywamy to metodą. To zachowanie obiektu. Zaimplementujmy to:
class Vehicle:
def __init__(self, number_of_wheels, type_of_tank, seating_capacity, maximum_velocity):
self.number_of_wheels = number_of_wheels
self.type_of_tank = type_of_tank
self.seating_capacity = seating_capacity
self.maximum_velocity = maximum_velocity
def number_of_wheels(self):
return self.number_of_wheels
def set_number_of_wheels(self, number):
self.number_of_wheels = number
Jest to implementacja dwóch metod: number_of_wheels
(liczba kółek) i set_number_of_wheels
(liczba zestawów kółek). Nazywamy je getter
i setter
, ponieważ pierwszy otrzymuje wartość atrybutu, a drugi ustawia nową wartość atrybutu.
W Pythonie możemy to zrobić używając @property (decorators)
do zdefiniowania getters
i setters
. Sprawdźmy to z kodem:
class Vehicle:
def __init__(self, number_of_wheels, type_of_tank, seating_capacity, maximum_velocity):
self.number_of_wheels = number_of_wheels
self.type_of_tank = type_of_tank
self.seating_capacity = seating_capacity
self.maximum_velocity = maximum_velocity
@property
def number_of_wheels(self):
return self.__number_of_wheels
@number_of_wheels.setter
def number_of_wheels(self, number):
self.__number_of_wheels = number
I możemy użyć tych metod jako atrybutów:
class Vehicle:
def __init__(self, number_of_wheels, type_of_tank, seating_capacity, maximum_velocity):
self.number_of_wheels = number_of_wheels
self.type_of_tank = type_of_tank
self.seating_capacity = seating_capacity
self.maximum_velocity = maximum_velocity
@property
def number_of_wheels(self):
return self.__number_of_wheels
@number_of_wheels.setter
def number_of_wheels(self, number):
self.__number_of_wheels = number
Jest to odmienne od definiowania metod. Metody działają jak atrybuty. Na przykład, gdy ustawimy nową liczbę kół, nie zastosujemy dwóch jako parametru, ale ustawimy wartość 2
do number_of_wheels
. Jest to jeden ze sposobów zapisywania gettera pythonowego i kodu ustawiającego.
Ale możemy również użyć metod dla innych rzeczy, takich jak metoda make_noise
.
class Vehicle:
def __init__(self, number_of_wheels, type_of_tank, seating_capacity, maximum_velocity):
self.number_of_wheels = number_of_wheels
self.type_of_tank = type_of_tank
self.seating_capacity = seating_capacity
self.maximum_velocity = maximum_velocity
def make_noise(self):
print('wruuuuum')
Kiedy wywołujemy tę metodę, po prostu zwraca ciąg „wruuuuum”.
tesla_model_s = Vehicle(4, 'electric', 5, 250)
tesla_model_s.make_noise() # wruuuuum
Enkapsulacja: Ukrywanie informacji
Enkapsulacja to mechanizm ograniczający bezpośredni dostęp do danych i metod obiektów. Jednocześnie ułatwia on działanie na tych danych (metod obiektów).
Enkapsulacja może być używana do ukrywania części danych i funkcji. Zgodnie z tą definicją, enkapsulacja oznacza, że wewnętrzna reprezentacja obiektu jest na ogół ukryta poza definicją obiektu. - Wikipedia
Cała wewnętrzna reprezentacja obiektu jest ukryta z zewnątrz. Tylko obiekt może wchodzić w interakcje z jego danymi wewnętrznymi. Po pierwsze, musimy zrozumieć, jak działają publiczne i niepubliczne zmienne i metody instancji.
Zmienne instancji publicznej
Dla klasy Pythona możemy zainicjować zmienną instancji publicznej w ramach naszej metody konstruktora.
W metodzie konstruktora:
tesla_model_s = Vehicle(4, 'electric', 5, 250)
tesla_model_s.make_noise() # VRUUUUUUUM
Tutaj stosujemy wartość first_name
jako argument zmiennej publicznej instancji.
tk = Person('TK')
print(tk.first_name) # => TK
W ramach klasy:
class Person:
first_name = 'TK'
Tutaj nie musimy stosować first_name
jako argumentu, a wszystkie obiekty instancji będą miały atrybut klasy zainicjowane z TK
.
tk = Person()
print(tk.first_name) # => TK
Dowiedzieliśmy się teraz, że możemy używać publicznych zmiennych instancji i atrybutów klas. Inną interesującą rzeczą w części publicznej jest to, że możemy zarządzać wartością zmiennej. Co to znaczy? Nasz obiekt może zarządzać wartością zmiennej: get
(pobierz) i set
(ustaw wartości zmiennych).
Mając na uwadze klasę Person
, chcemy ustawić inną wartość dla zmiennej first_name
:
tk = Person('TK')
tk.first_name = 'Kaio'
print(tk.first_name) # => Kaio
Ustawiamy inną wartość (kaio
) na zmienną instancji first_name
i aktualizujemy wartość. Możemy to zrobić, gdyż jest to zmienna publiczna.
Niepubliczna zmienna instancji
Nie używamy tutaj terminu „prywatny”, ponieważ żaden atrybut nie jest naprawdę prywatny w Pythonie (bez generalnie niepotrzebnej ilości pracy). - PEP 8
Jako zmienną instancji publicznej możemy zdefiniować niepubliczną zmienną instancji zarówno w metodzie konstruktora, jak i w klasie. Różnica składniowa jest następująca: w przypadku niepublicznych zmiennych instancji użyj znaku podkreślenia (_
) przed nazwą zmiennej.
„Prywatne zmienne instancji, do których nie można uzyskać dostępu z wyjątkiem wewnątrz obiektu, nie istnieją w Pythonie. Istnieje jednak konwencja, po której następuje większość kodu Pythona: nazwa poprzedzona znakiem podkreślenia (np. _spam) powinna być traktowana jako niepubliczna część API (niezależnie od tego, czy jest to funkcja, metoda czy element danych)”- Python Software Foundation
Tutaj przykład:
class Person:
def __init__(self, first_name, email):
self.first_name = first_name
self._email = email
Czy widziałeś zmienną email
? W ten sposób definiujemy zmienną niepubliczną:
tk = Person('TK', '[email protected]')
print(tk._email) # [email protected]
Możemy go uzyskać i zaktualizować. Zmienne niepubliczne są tylko konwencją i powinny być traktowane jako niepubliczna część API.
Używamy więc metody, która pozwala nam to zrobić w naszej definicji klasy. Zaimplementujemy dwie metody (email
i update_email
), aby to zrozumieć:
class Person:
def __init__(self, first_name, email):
self.first_name = first_name
self._email = email
def update_email(self, new_email):
self._email = new_email
def email(self):
return self._email
Teraz możemy aktualizować i uzyskiwać dostęp do niepublicznych zmiennych za pomocą tych metod.
tk = Person('TK', '[email protected]')
print(tk.email()) # => [email protected]
# tk._email = '[email protected]' -- treat as a non-public part of the class API
print(tk.email()) # => [email protected]
tk.update_email('[email protected]')
print(tk.email()) # => [email protected]
- Zainicjowaliśmy nowy obiekt o nazwie
first_name
TK ie-mail
[email protected] - Wywołaliśmy
email
, zyskujemy dostęp do zmiennej niepublicznej za pomocą metody - Próbujemy ustawić nowy
email
z naszej klasy - Musimy traktować niepubliczną zmienną jako niepubliczną część API
- Aktualizujemy zmienną niepubliczną za pomocą naszej metody instancji
- Sukces! Możemy zaktualizować go w naszej klasie za pomocą metody pomocniczej
Metoda publiczna
Dzięki metodom publicznym możemy również wykorzystać je do naszej klasy.
class Person:
def __init__(self, first_name, age):
self.first_name = first_name
self._age = age
def show_age(self):
return self._age
Przetestujmy to:
tk = Person('TK', 25)
print(tk.show_age()) # => 25
Świetnie, działa bez problemu.
Metoda niepubliczna
Dzięki metodom niepublicznym nie jesteśmy w stanie zrobić tego samego. Zaimplementujmy tę samą klasę Person
, ale teraz z niepubliczną metodą show_age
, używając podkreślenia (_
).
class Person:
def __init__(self, first_name, age):
self.first_name = first_name
self._age = age
def _show_age(self):
return self._age
A teraz spróbujemy wywołać tę niepubliczną metodę za pomocą naszego obiektu:
tk = Person('TK', 25)
print(tk._show_age()) # => 25
Możemy uzyskać dostęp i zaktualizować to. Metody niepubliczne są tylko pewną konwencją i powinny być traktowane jako niepubliczna część API.
Oto przykład, w jaki sposób możemy go wykorzystać:
class Person:
def __init__(self, first_name, age):
self.first_name = first_name
self._age = age
def show_age(self):
return self._get_age()
def _get_age(self):
return self._age
tk = Person('TK', 25)
print(tk.show_age()) # => 25
Tutaj mamy metodę niepubliczną ‘_get_age’ i metodę publiczną show_age
. Show_age
może być używany przez nasz obiekt (poza naszą klasą) i _get_age
używany tylko wewnątrz naszej definicji klasy (wewnątrz metody show_age
). Ale znowu: zgodnie z konwencją.
Podsumowanie enkapsulacji
Dzięki enkapsulacji możemy zapewnić, że wewnętrzna reprezentacja obiektu nie jest widoczna z zewnątrz.
Dziedziczenie: Zachowania i cechy
Niektóre obiekty mają pewne cechy wspólne: ich zachowania i cechy. Na przykład - ja odziedziczyłem po ojcu pewne cechy i zachowania. Odziedziczyłem jego oczy i włosy jako cechy charakterystyczne, a jego niecierpliwość i introwersję jako zachowania. W programowaniu obiektowym klasy mogą dziedziczyć wspólne cechy (dane) i zachowania (metody) z innej klasy.
Zobaczmy inny przykład i zaimplementujmy go w Pythonie. Wyobraźmy sobie samochód. Liczba kół, pojemność i maksymalna prędkość to cechy samochodu. Możemy powiedzieć, że klasa ElectricCar
dziedziczy te same atrybuty ze zwykłej klasy samochodów.
class Car:
def __init__(self, number_of_wheels, seating_capacity, maximum_velocity):
self.number_of_wheels = number_of_wheels
self.seating_capacity = seating_capacity
self.maximum_velocity = maximum_velocity
Klasę naszego samochodówu zaimplementujemy tak:
my_car = Car(4, 5, 250)
print(my_car.number_of_wheels)
print(my_car.seating_capacity)
print(my_car.maximum_velocity)
Po jednym zainicjowaniu, możemy używać wszystkich utworzonych zmiennych instancji.
W Pythonie do klasy “dziedziczonej” stosujemy klasę nadrzędną jako parametr. Klasa ElectricCar
może dziedziczyć po naszej klasie samochodów.
class ElectricCar(Car):
def __init__(self, number_of_wheels, seating_capacity, maximum_velocity):
Car.__init__(self, number_of_wheels, seating_capacity, maximum_velocity)
Proste. Nie musimy implementować żadnej innej metody, ponieważ ta klasa już ją posiada (odziedziczona z klasy Car
). Udowodnijmy to:
my_electric_car = ElectricCar(4, 5, 250)
print(my_electric_car.number_of_wheels) # => 4
print(my_electric_car.seating_capacity) # => 5
print(my_electric_car.maximum_velocity) # => 250
Pięknie!
To jest to!
Dowiedzieliśmy się wielu rzeczy o podstawach Pythona. Ukończyłeś wstęp do treści o Pythonie i na pewno nie było tak trudno :)