Co to jest __init__ w Pythonie? [With Examples]

Chcesz zacząć projektować obiektowo w Pythonie? Już dziś postaw pierwsze kroki, poznając metodę __init__ języka Python.

W tym samouczku omówimy podstawy klas i obiektów Pythona, a następnie przejdziemy do poznania metody __init__.

Pod koniec tego samouczka będziesz w stanie odpowiedzieć na następujące pytania:

  • Co to są zmienne instancji lub atrybuty instancji?
  • W jaki sposób metoda init pomaga w inicjowaniu atrybutów instancji?
  • Jak możemy ustawić wartości domyślne dla atrybutów?
  • Jak możemy używać metod klasowych jako konstruktorów do tworzenia obiektów?

Zacznijmy.

Klasy i obiekty Pythona

Klasy są podstawą programowania obiektowego w Pythonie. Możemy utworzyć klasę i zdefiniować atrybuty oraz metody — aby powiązać ze sobą dane i powiązane z nimi funkcje.

Po utworzeniu klasy możemy użyć jej jako planu (lub szablonu) do tworzenia obiektów (instancji).

👩‍🏫Przykładowy czas! Stwórzmy klasę Pracownik, w której każdy obiekt tej klasy ma następujące atrybuty:

  • full_name: pełne imię i nazwisko pracownika w formacie imię i nazwisko
  • emp_id: identyfikator pracownika
  • dział: dział, do którego należą
  • doświadczenie: liczba lat doświadczenia, jakie posiadają

Co to znaczy? 🤔

Każdy indywidualny pracownik będzie instancją lub obiektem klasy Pracownik. Każdy obiekt będzie miał własną wartość dla full_name, emp_id, departamentu i doświadczenia.

Te atrybuty są również nazywane zmiennymi instancji, a terminów atrybuty i zmienne instancji będziemy używać zamiennie.

Za chwilę przejdziemy do dodawania atrybutów. Na razie tworzymy klasę Employee w następujący sposób:

class Employee:
    pass

Użycie pass (jako symbolu zastępczego) pomaga nam uniknąć błędów podczas uruchamiania skryptu.

Chociaż obecna wersja klasy Pracownik nie jest zbyt pomocna, nadal jest to poprawna klasa. Możemy więc stworzyć obiekty klasy Pracownik:

employee_1 = Employee()

print(employee_1)
#Output: <__main__.Employee object at 0x00FEE7F0>

Możemy również dodać atrybuty i zainicjować je wartościami, jak pokazano:

employee_1.full_name="Amy Bell"
employee_1.department="HR"

Jednak takie podejście do dodawania atrybutów instancji jest zarówno nieefektywne, jak i podatne na błędy. Nie pozwala to również na użycie klasy jako szablonu do tworzenia obiektów. Tutaj pomaga metoda __init__.

Zrozumienie roli metody __init__ w klasie Pythona

Powinniśmy być w stanie zainicjować zmienne instancji podczas tworzenia instancji obiektu, a metoda __init__ pomaga nam to zrobić. Metoda __init__ jest wywoływana za każdym razem, gdy tworzony jest nowy obiekt klasy w celu zainicjowania wartości zmiennych instancji.

Jeśli programowałeś w języku takim jak C++, zobaczysz, że metoda __init__ działa podobnie do konstruktorów.

Definiowanie metody __init__

Dodajmy metodę __init__ do klasy Pracownik:

class Employee:
    def __init__(self, full_name,emp_id,department,experience):
        self.full_name = full_name
        self.emp_id = emp_id
        self.department = department
        self.experience = experience

Parametr self odnosi się do instancji klasy, a self.attribute inicjuje atrybut instancji do wartości po prawej stronie.

Możemy teraz tworzyć takie obiekty:

employee_2 = Employee('Bella Joy','M007','Marketing',3)
print(employee_2)
# Output: <__main__.Employee object at 0x017F88B0>

Kiedy drukujemy obiekty pracowników, nie otrzymujemy żadnych użytecznych informacji poza klasą, do której należą. Dodajmy metodę __repr__, która definiuje łańcuch reprezentujący klasę:

 def __repr__(self):
        return f"{self.full_name},{self.emp_id} from {self.department} with {self.experience} years of experience."

Dodając __repr__ do klasy Pracownik, mamy:

class Employee:
    def __init__(self, full_name,emp_id,department,experience):
        self.full_name = full_name
        self.emp_id = emp_id
        self.department = department
        self.experience = experience
    
     def __repr__(self):
        return f"{self.full_name},{self.emp_id} from {self.department} with {self.experience} years of experience."

Teraz obiekty pracowników mają pomocny ciąg reprezentacji:

print(employee_2)
# Output: Bella Joy,M007 from Marketing with 3 years of experience.

Niektóre konwencje

Zanim przejdziemy dalej, oto kilka uwag:

  • Użyliśmy self jako pierwszego parametru w metodzie __init__, aby odwołać się do samej instancji klasy, i użyliśmy self.attribute_name do zainicjowania różnych atrybutów. Używanie self jest preferowaną konwencją (możesz jednak użyć dowolnej innej nazwy).
  • Podczas definiowania metody __init__ ustawiamy nazwy parametrów w definicjach __init__ tak, aby odpowiadały nazwom atrybutów. Poprawia to czytelność.

Jak dodać wartości domyślne dla atrybutów

W przykładzie, który do tej pory zakodowaliśmy, wymagane są wszystkie atrybuty. Oznacza to, że utworzenie obiektu zakończy się sukcesem tylko wtedy, gdy przekażemy wartości dla wszystkich pól do konstruktora.

Spróbuj utworzyć instancję obiektu klasy Pracownik bez przekazywania wartości atrybutu doświadczenie:

employee_3 = Employee('Jake Lee','E001','Engineering')

Otrzymasz następujący błąd:

Traceback (most recent call last):
  File "main.py", line 22, in <module>
    employee_3 = Employee('Jake Lee','E001','Engineering')
TypeError: __init__() missing 1 required positional argument: 'experience'

Ale jeśli chcesz, aby niektóre atrybuty były opcjonalne, możesz to zrobić, podając wartości domyślne dla tych atrybutów podczas definiowania metody __init__.

Tutaj podajemy domyślną wartość 0 dla atrybutu doświadczenie:

class Employee:
    def __init__(self, full_name,emp_id,department,experience=0):
        self.full_name = full_name
        self.emp_id = emp_id
        self.department = department
        self.experience = experience
    
     def __repr__(self):
        return f"{self.full_name},{self.emp_id} from {self.department} with {self.experience} years of experience."

Obiekt pracownik_3 jest tworzony bez wartości dla atrybutu doświadczenie; dla doświadczenia używana jest domyślna wartość 0.

employee_3 = Employee('Jake Lee','E001','Engineering')
print(employee_3.experience)
# Output: 0

Konstruktory klas alternatywnych przy użyciu metod klasowych

Do tej pory widzieliśmy tylko, jak zdefiniować metodę __init__ i ustawić domyślne wartości atrybutów, gdy są potrzebne. Wiemy również, że musimy przekazać wartości wymaganych atrybutów w konstruktorze.

Czasami jednak wartości tych zmiennych instancji (lub atrybutów) mogą być dostępne w innej strukturze danych, takiej jak krotka, słownik lub łańcuch JSON.

Więc co robimy?

Weźmy przykład. Załóżmy, że mamy wartości zmiennej instancji w słowniku Pythona:

dict_fanny = {'name':'Fanny Walker','id':'H203','dept':'HR','exp':2}

Możemy dotknąć słownika i uzyskać wszystkie atrybuty w ten sposób:

name = dict_fanny['name']
id = dict_fanny['id']
dept = dict_fanny['dept']
exp = dict_fanny['exp']

Następnie możesz utworzyć obiekt, przekazując te wartości do konstruktora klasy:

employee_4 = Employee(name, id, dept, exp)
print(employee_4)
# Output: Fanny Walker,H203 from HR with 2 years of experience.

Pamiętaj: musisz to zrobić dla każdego nowego obiektu, który tworzysz. Takie podejście jest nieefektywne i zdecydowanie możemy zrobić to lepiej. Ale jak?

W Pythonie możemy używać metod klasowych jako konstruktorów do tworzenia obiektów klasy. Aby utworzyć metodę klasy, używamy dekoratora @classmethod.

Zdefiniujmy metodę, która analizuje słownik, pobiera wartości zmiennych instancji i używa ich do konstruowania obiektów pracowników.

    @classmethod
    def from_dict(cls,data_dict):
        full_name = data_dict['name']
        emp_id = data_dict['id']
        department = data_dict['dept']
        experience = data_dict['exp']
        return cls(full_name, emp_id, department, experience)

Kiedy musimy utworzyć obiekty przy użyciu danych ze słownika, możemy użyć metody klasy from_dict().

💡 Zwróć uwagę na użycie cls w metodzie klasowej zamiast self. Tak jak używamy self w odniesieniu do instancji, cls jest używane w odniesieniu do klasy. Ponadto metody klasowe są powiązane z klasą, a nie z obiektami.

Kiedy więc wywołujemy metodę klasy from_dict() w celu utworzenia obiektów, wywołujemy ją w klasie Employee:

emp_dict = {'name':'Tia Bell','id':'S270','dept':'Sales','exp':3}
employee_5 = Employee.from_dict(emp_dict)
print(employee_5)
# Output: Tia Bell,S270 from Sales with 3 years of experience.

Teraz, jeśli mamy słownik dla każdego z n pracowników, możemy użyć metody klasy from_dict() jako konstruktora do tworzenia instancji w obiektach — bez konieczności pobierania natychmiastowych wartości zmiennych ze słownika.

📝 Uwaga dotycząca zmiennych klasowych

Tutaj zdefiniowaliśmy metodę klasową, która jest powiązana z klasą, a nie z poszczególnymi instancjami. Podobnie jak w przypadku metod klasowych, możemy również mieć zmienne klasowe.

Podobnie jak metody klasowe, zmienne klasowe są powiązane z klasą, a nie z instancją. Gdy atrybut przyjmuje stałą wartość dla wszystkich instancji klasy, możemy rozważyć zdefiniowanie ich jako zmiennych klasowych.

Często zadawane pytania

1. Dlaczego potrzebujesz metody __init__ w Pythonie?

Metoda __init__ w definicji klasy pozwala nam zainicjować atrybuty lub zmienne instancji wszystkich instancji klasy. Metoda __init__ jest wywoływana za każdym razem, gdy tworzona jest nowa instancja klasy.

2. Czy w klasie Pythona można mieć wiele metod __init__?

Celem posiadania wielu metod __init__ w klasie Pythona jest zapewnienie wielu konstruktorów, którzy tworzą instancje obiektów. Ale nie możesz zdefiniować wielu metod __init__. Jeśli zdefiniujesz wiele metod __init__, druga i najnowsza implementacja zastąpi pierwszą. Możesz jednak użyć dekoratora @classmethod do zdefiniowania metod klasowych, które mogą być używane jako konstruktory do tworzenia instancji obiektów.

3. Co się stanie, jeśli nie zdefiniujesz metody __init__ w klasie?

Jeśli nie zdefiniujesz metody __init__, nadal możesz tworzyć instancje obiektów. Będziesz jednak musiał ręcznie dodać zmienne instancji i przypisać wartości do każdej z nich. Nie będziesz mógł przekazać wartości zmiennych instancji w konstruktorze. Jest to nie tylko podatne na błędy, ale także mija się z celem posiadania klasy jako planu, z którego możemy tworzyć instancje obiektów.

4. Czy możesz mieć domyślne wartości argumentów w metodzie __init__?

Tak, podczas definiowania metody __init__ można podać wartości domyślne dla jednego lub więcej atrybutów. Podanie wartości domyślnych pomaga uczynić te atrybuty opcjonalnymi w konstruktorze. Atrybuty przyjmują wartości domyślne, gdy nie przekazujemy wartości dla tych atrybutów w konstruktorze.

5. Czy możesz modyfikować atrybuty poza metodą __init__?

Tak, zawsze możesz zaktualizować wartość atrybutu poza metodą __init__. Możesz także dynamicznie dodawać nowe atrybuty do instancji po jej utworzeniu.

Wniosek

W tym samouczku nauczyliśmy się, jak używać metody __init__ do inicjowania wartości zmiennych instancji. Chociaż jest to proste, może być powtarzalne — zwłaszcza gdy masz wiele atrybutów.

Jeśli jesteś zainteresowany, możesz zapoznać się z modułem dataclasses. W Pythonie 3.7 i nowszych można użyć wbudowanego modułu klas danych do tworzenia klas danych, które przechowują dane. Oprócz domyślnych implementacji __init__ i innych powszechnie używanych metod; są wyposażone w wiele fajnych funkcji podpowiedzi typu, złożonych wartości domyślnych i optymalizacji.

Następnie dowiedz się więcej o if __name__==’__main__’ w Pythonie.