OOP, nie rozumiem części kodu

OOP, nie rozumiem części kodu
Tomasz Przybyło
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 2 lata
  • Postów:18
0

Dobry. Mam tutaj kod i nie rozumiem jego części

Kopiuj
class Song:
    """Class to represent a song

    Attributes:
        title (str): The title of the song
        artist (Artist): An artist object representing the songs creator.
        duration (int): The duration of the song in seconds.  May be zero
    """

    def __init__(self, title, artist, duration=0):
        self.title = title
        self.artist = artist
        self.duration = duration


class Album:
    """ Class to represent an Album, using it's track list

    Attributes:
        name (str): The name of the album.
        year (int): The year was album was released.
        artist: (Artist): The artist responsible for the album. If not specified,
        the artist will default to an artist with the name "Various Artists".
        tracks (List[Song]):  A list of the songs on the album.

    Methods:
        add_song: Used to add a new song to the album's track list.
    """

    def __init__(self, name, year, artist=None):
        self.name = name
        self.year = year
        if artist is None:
            self.artist = Artist("Various Artists")
        else:
            self.artist = artist

        self.tracks = []

    def add_song(self, song, position=None):
        """Adds a song to the track list

        Args:
            song (Song): A song to add.
            position (Optional[int]): If specified, the song will be added to that position
                in the track list - inserting it between other songs if necessary.
                Otherwise, the song will be added to the end of the list.
        """
        if position is None:
            self.tracks.append(song)
        else:
            self.tracks.insert(position, song)


class Artist:
    """Basic class to store artist details.

    Attributes:
        name (str): The name of the artist.
        albums (List[Album]): A list of the albums by this artist.
            The list includes only those albums in this collection, it is
            not an exhaustive list of the artist's published albums.

    Methods:
        add_album: Use to add a new album to the artist's albums list
    """

    def __init__(self, name):
        self.name = name
        self.albums = []

    def add_album(self, album):
        """Add a new album to the list.

        Args:
            album (Album): Album object to add to the list.
                If the album is already present, it will not added again (although this is yet to implemented).
        """
        self.albums.append(album)


def load_data():
    new_artist = None
    new_album = None
    artist_list = []

    with open("albums.txt", "r") as albums:
        for line in albums:
            # data row should consist of (artist, album, year, song)
            artist_field, album_field, year_field, song_field = tuple(line.strip('\n').split('\t'))
            year_field = int(year_field)
            print("{}:{}:{}:{}".format(artist_field, album_field, year_field, song_field))

            if new_artist is None:
                new_artist = Artist(artist_field)
            elif new_artist.name != artist_field:
                # We've just read details for a new artist
                # store the current album in the currents artists collection then create a new artist object
                new_artist.add_album(new_album)
                artist_list.append(new_artist)
                new_artist = Artist(artist_field)
                new_album = None

            if new_album is None:
                new_album = Album(album_field, year_field, new_artist)
            elif new_album.name != album_field:
                # We've just read a new album for the current artist
                # store the current album in the artist's collection then create a new album object
                new_artist.add_album(new_album)
                new_album = Album(album_field, year_field, new_artist)

            # create a new song object and add it to the current album's collection
            new_song = Song(song_field, new_artist)
            new_album.add_song(new_song)

        # After read the last line of the text file, we will have an artist and album that haven't
        #  been store - process them now
        if new_artist is not None:
            if new_album is not None:
                new_artist.add_album(new_album)
            artist_list.append(new_artist)

    return artist_list


def create_checkfile(artist_list):
    """Create a check file from the object data for comparison with the original file"""
    with open("checkfile.txt", 'w') as checkfile:
        for new_artist in artist_list:
            for new_album in new_artist.albums:
                for new_song in new_album.tracks:
                    print("{0.name}\t{1.name}\t{1.year}\t{2.title}".format(new_artist, new_album, new_song),
                        file=checkfile)


if __name__ == '__main__':
    artists = load_data()
    print("There are {} artists".format(len(artists)))

    create_checkfile(artists)

Kompletnie nie rozumiem cześci od 91 do 107. Bylby ktos w stanie mi to wyjaśnić ?

Althorion
Moderator C/C++
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 17 godzin
  • Postów:1605
1
  1. Linijka 84. otwiera plik albums.txt, 85. czyta go linia po linii. Komentarz w 88. mówi, że każda linijka to (artist, album, year, song).
  2. Zmienna new_artist jest inicjowana None w linijce 80. Potem linia 91. sprawdza, czy dalej tak jest (czyli nie zostało to ustawione na nic sensownego), i jeśli tak, to podstawia pod to utworzonego Artistartist_field. Widzimy z konstruktora z linii 66., że taka instancja ma nazwę ustawioną na artist_field i pustą listę albumów.
  3. Jeśli natomiast ta zmienna jest już ustawiona, to linia 93. sprawdza, czy jest ustawiona na to samo, co właśnie zostało wczytane do artist_field. Jeśli tak, to poprzedniemu artyście dodaje nowy album (96.), dodaje tego starego artystę do listy artystów (97.) i ustawia zmienną new_artist na, wreszcie, tego nowego wykonawcę (98.). Po czym new_album jest ustawiane na None.
  4. Linie 101. do 107. robią coś bardzo podobnego: jeśli nie ma ustawionego new_album, to go ustawia, a jeśli nie jest, to patrzy czy ten nowo wczytany album ma taką samą nazwę, jak poprzedni album, na którym operowano, jeśli nie, to dodaje aktualnemu artyście (zmienna new_artist — tak, nazwa jest bardzo myląca…) ten album i ustawia zmienną new_album na odczytany album.

Ogólnie kod mocno łotafakowy, szczególnie nazewnictwo new_artistnew_album, zamiast chociażby last_processed_artistlast_processed_album są bardzo mylące, ale i sama metoda uzupełniania tego jest mocno dziwna…

Tomasz Przybyło
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 2 lata
  • Postów:18
0

Nie rozumiem dlaczego tam jest

Kopiuj
new_artist.name != artist_field

DLaczego różne

edytowany 2x, ostatnio: Tomasz Przybyło
Althorion
Moderator C/C++
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 17 godzin
  • Postów:1605
1

By nie utworzyć drugi raz tego samego artysty. Bardzo karkołomny sposób na to, zakładający bardzo dużo niewymuszonych w żaden sposób rzeczy o wejściowym pliku tekstowym (konkretnie: odpowiedniego posortowania danych). new_artist przechowuje aktualnie „obrabianego” artystę, więc ta linijka sprawdza, czy nam się przytrafił jakiś nowy, którego trzeba utworzyć, czy też dalej operujemy na tym samym. Nazwa zmiennej, jak pisałem, w aktywny sposób myląca…

Tomasz Przybyło
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 2 lata
  • Postów:18
0

Pare rzeczy mi wyjaśniłeś, jednak niektóre nadal są dla mnie niejasne. Muszę jeszcze kilka razy przeczytać kod oraz to co mi napisałeś. W razie dalszych problemów jeszcze się odezwę :D dzięki za pomoc

MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:4 minuty
1

Nie dziwię się, że nie rozumiesz tego kodu, bo jest on kiepsko napisany (nie jest najgorszy jaki można zobaczyć).
Radziłbym jednak mieć ograniczone zaufanie do autora.

Ja bym napisał to inaczej:

  1. użyłbym gotowego modułu do prasowania CSV (python3 ma go chyba w standardzie)
  2. żeby utrzymywać jeden obiekt na artystę, album, piosenkę użyłbym słownika
  3. podzieliłbym kod na więcej metod

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
Tomasz Przybyło
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 2 lata
  • Postów:18
0

Jest to część kursu na udemy o OOP. Może to jakis wstęp i później będzie to lepiej napisane. Mogłoby tak być ? Jednak dla mnie ten wstęp nie jest zbyt jasny.
Najgorsze jest to, że nie bardzo rozumiem tej części, a pare następnych filmikó składa sie właśnie z tego kodu. Nie chciałbym następnych pomijać, żeby nie opuścić czegoś istotnego. Właściwie chciałbym zapytać czy do analizy danych i ds oop jest istotne ?

edytowany 1x, ostatnio: Tomasz Przybyło
MarekR22
A ja byłem przekonany, że to jakiś blog mało doświadczonego programisty z parciem na szkło. Jak to jest płatny kurs to jest to prawdziwa żenada.
Althorion
Moderator C/C++
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 17 godzin
  • Postów:1605
1

Oj. Jak to jest kurs, to ja bym uciekał. I to całkiem szybko.

Raz, że niejasny, dwa że to po prostu zły kod jest. Więc nawet jak w końcu zrozumiesz, o co chodzi, to zrozumiesz kod, którego w życiu nie powinieneś powielać…

A OOP to tylko jeden z paradygmatów. Może i najbardziej popularny, bo faktycznie wygodny w wielu zastosowaniach, więc wypada przynajmniej rozumieć, na czym to polega, ale z pewnością nie trzeba być w tym zakochanym i samemu używać…

Tomasz Przybyło
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 2 lata
  • Postów:18
0
Kopiuj
https://www.udemy.com/course/python-the-complete-python-developer-course/

sugerowałem się opiniami i dotychczas z mojej perspektywy wszystko dobrze było wyjaśnione.

semicolon
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:114
1

Autor kodu widać chciał przedstawić jak graf mutowalnych obiektów ułatwia tworzenie funkcji takich jak create_checkfile.

Może i wygodnie mu się tak skanuje te obiekty przy użyciu pętli.

Ale zbudowanie takiego grafu nie zawsze jest oczywiste i sensowne. Ten kod jest tego przykładem.

Na przykład jeśli kolejność piosenek nie będzie w pliku csv posortowana to w ramach tworzenia kodu może dojść do stworzenia paru instancji autora, paru instancji albumu. Majac kilka obiektów reprezentujących ten sam byt nie trudno o kolejne błędy jeśli zajdzie potrzeba jakieś modyfikacji (np. na skutek aktualizacji nazwy autora).

Poza tym z punktu widzenia klas ja nie wiem czy te klasy wnoszą jakąś wartość. Równie dobrze mogłaby tu być użyte słowniki skoro i tak enkapsulacja jest olana.

Tomasz Przybyło
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 2 lata
  • Postów:18
0

Nie jestem jeszcze pewien, ale po komentarzach, które przeglądałem w poszukiwaniu odpowiedzi, coś przewinęło się o sortowaniu w późniejszych lekcjach.
Poza tym też się zastanawiałem czego tutaj są użyte klasy, gdzie można by to zrobić na funkcjach i słowniku.
Próbuję teraz przebrnąć przez kod. Wziąłem kartkę i notuję co się dzieje po kolei wraz z ewentualnymi pytaniami. Debugger jest dla słąbych xD a tak serio nie umiem z niego korzystać.

edytowany 2x, ostatnio: Tomasz Przybyło
semicolon
Klasy to sposób na modelowanie danych. Gdy masz obiekt wybranej klasy masz w pewien sposób pewność, że ten obiekt ma pewien zbiór atrybutów. Kod z klasami może być skanowany przez mypy pod kątem błędow, no i też IDE bardziej pomaga gdy wie z czym teraz pracujesz. Natomiast słownik to bardzo ogólny byt i może zaskoczyć brakiem konkretnego atrybutu (w tym przypadku klucza) i zdecydowanie wymaga większej dyscypliny w kodzie, aby nie doprowadzać do oczywistych błędów.
semicolon
Nie mniej stosowanie klas w banalnych przypadkach to typowy przerost formy nad treścią.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)