OOP, nie rozumiem części kodu

0

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

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ć ?

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…

0

Nie rozumiem dlaczego tam jest

new_artist.name != artist_field

DLaczego różne

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…

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

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
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 ?

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ć…

0
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.

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.

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ć.

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