Funkcja super() jak działa, jak używać, argumenty ?

0

Cześć
Przerabiam właśnie książkę "Python dla każdego. Podstawy programowania. Wydanie III"
Jestem na dziedziczeniu w OOP
Niestety na trafiłem na funkcję super() której za nic nie mogę zrozumieć
Kod autora książki

# Gra w karty 3.0
#  demonstruje dziedziczenie -  przeslanianie metod

class Card(object):
	"""Karta do gry"""
	RANKS = ["A","2","3","4","5","6","7","8","9","10","j","Q","K",]

	SUITS = ["c","d","h","s"]

	def __init__(self,rank, suit):
		self.rank = rank
		self.suit = suit

	def __str__(self):
		rep = self.rank + self.suit
		return rep

class Unprintable(Card):
	"""Karta ktorej ranga i kolor nie sa ujawnione przy jej wyswietleniu"""
	def __str__(self):
		return "<utajniona>"

class Positionable_Card(Card):
	"""Karta ktora moze byc zakryta lub odkryta"""
	def __init__(self, rank, suit, face_up=True):
		super(Positionable_Card, self).__init__(rank, suit)
		self.is_face_up = face_up

	def __str__(self):
		if self.is_face_up:
			rep = super(Positionable_Card, self).__str__()
		else:
			rep = "XX"
		return rep

	def flip(self):
		self.is_face_up = not self.is_face_up

Konkretnie chodzi mi o linię 26 "super(Positionable_Card, self).init(rank, suit)"
Jak to działa skąd się tam wzięły te argumenty i dlaczego?

2

Wywołanie super odnosi się do klasy nadrzędnej, dzięki czemu możesz odnieść się do metod, które twoja pochodna klasa przysłania.

0

Metoda super() konkretnie wywołuje tutaj konstruktor klasy nadrzędnej. Kod:

    def __init__(self, rank, suit, face_up=True):
        super(Positionable_Card, self).__init__(rank, suit)
        self.is_face_up = face_up

jest równoważny

    def __init__(self,rank, suit, face_up=True):
        #Właściwości z konstruktora nadklasy
        self.rank = rank
        self.suit = suit
        #Dodatkowa właściwość klasy pochodnej
        self.is_face_up = face_up

Dziedziczenie za pomocą klas jest pewną abstrakcją odpowiadającą za mechanizm kompozycji. Dzięki temu nie musisz za każdym razem przepisywać metody konstruktora.klasy nadrzędnej. Zamiast tego wstrzykujesz go metodą super do klasy pochodnej, a potem możesz rozszerzyć lub/i nadpisać jej właściwości.

1

Jak wyżej^. Z tego co widzę kod pochodzi z Pythona 2. W Pythonie 3 składnia jest nieco inna:

super().__init__(rank, suit)

Czyli nie musimy wskazywać nazwy klasy, której funkcje nadrzędne chcemy wywołać.

Super korzysta z MRO - Method Resolution Order. W skrócie wyszukuje wskazaną funkcję (dla nas __init__) po kolei wedle MRO. Gdyby klasa Positionable_Card wyglądała tak: Positionable_Card(cardA, cardB) to Python najpierw "zajrzy" do cardA. Jeżeli cardA będzie miało metodę__init__ również z wywołaniem super().__init__ to zostanie przeszukana kolejna klasa wedle MRO (czyli cardB).Gdyby klasa cardA nie miała __init__ to Python przeszuka kolejną klasę wedle MRO. Jeżeli nic nie znajdzie to wywoła wyjątek AttributeError - brak metody o określonej nazwie.

0

Witam. Przyznam, że ten temat jest znajdowany przez google po wpisaniu "do czego służy super() Python" więc postanowiłem, że się dopiszę zamiast zakładać nowy temat. Poniżej pewien kod (pisany w Python 3.7) i pytanie do niego:

class czlowieczek:
    def __init__(self, imie, nazwisko):
        self.nazwisko = nazwisko
        self.imie = imie


cz1 = czlowieczek("Jan", "Kowalski")
print(cz1.imie)
print(cz1.nazwisko)

class dziecko (czlowieczek):
    def __init__(self, imie, nazwisko, imie_ojca):
        czlowieczek.__init__(self, imie, nazwisko)
        self.imie_ojca = imie_ojca

cz2 = dziecko("Stefanek", "Kowalski", "Jan")
print(cz2.imie)
print(cz2.nazwisko)
print(cz2.imie_ojca) 

Jedna z linijek wygląda tak:

        czlowieczek.__init__(self, imie, nazwisko)

Zauważyłem, że w przypadku tego kodu mogę użyć dla tej linijki inny zapis w postaci:

super().__init__(imie, nazwisko)

Osiągam dokładnie taki sam efekt. Jaka jest różnica między tymi zapisami ? Ewentualnie w jakim przypadku nie da się zastosować któregoś sposobu zapisu ?

0

Jakby to ująć, można dodawanie zapisać tak:

>>> 2+2
4

A można i tak:

>>> (2).__add__(2)
4

Działa tak samo co nie...? Ale jest raczej mniej czytelne. Język udostępnia konstrukcje pozwalające zrobić coś ładniej, co się zwie "cukrem skladniowym", aby nie trzeba było być świetnie obeznanym w bebechach języka - tu jest to fakt, że dodawanie w istocie wywołuje magiczną metodę __add__ - dla liczb generalnie to bez znaczenia, ale w końcu możesz dodawać i obiekty.

Tak, że na pierwszy rzut oka różnica między nazwa_klasy.metoda(self, argument), a super().metoda(argument) zdaje się sprowadzać do tego, że w drugim przypadku nie musisz zawsze pamiętać nazwy swojej nadklasy, co jest wygodniejsze w stosowaniu. Być może ma to jakieś jeszcze śmieszne efekty uboczne, które się unaoczniają przy jakichś edge-case'ach, pokroju tych różności, co niedawno ktoś wrzucił na mikroblog (https://github.com/satwikkansal/wtfpython), na przykład narusza to jakoś MRO (nigdy nie pamiętam jak to działa), aczkolwiek nie powinno to być problemem, bo każdy porządny programista będzie raczej używał super(), bo to bardziej pytoniczne i tak się po prostu robi.

A tutaj a szybko wyguglane mądrości ze SO https://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods, w które już mi się nie chce wgłębiać o tej porze.

1 użytkowników online, w tym zalogowanych: 0, gości: 1