2
respostas

Implementação de duck typing e classes abstratas

from abc import ABC, abstractmethod, abstractproperty


class Watchable:
    _id_tracker = 0

    def __init__(self, name, year):
        self._name = name.title()
        self.year = year
        self._likes = 0
        self._id = self.new_id()

    def __str__(self):
        return f"{self.name} ({self.year}) - {self.likes} likes"

    def __repr__(self):
        return f"{self.__class__.__name__}(name={self.name}, year={self.year}, likes={self.likes}, id={self.id})"

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, new_name):
        if not new_name:
            raise ValueError("Gotta have a name!")
        self._name = new_name.title()

    @property
    def likes(self):
        return self._likes

    @likes.setter
    def likes(self, new_amount):
        if not isinstance(new_amount, int):
            raise TypeError("Amount of likes needs to be an integer.")
        if new_amount < 0:
            raise ValueError("There are no negative likes.")
        self._likes = new_amount

    @property
    def id(self):
        return self._id

    @property
    def type(self):
        return self.__class__.__name__

    @classmethod
    def new_id(cls):
        cls._id_tracker += 1
        return cls._id_tracker

    def add_like(self, occurrences):
        if occurrences < 0:
            raise ValueError("Can't decrement likes.")
        self.likes += occurrences

    def _add_trashcan_icon(self):
        return f" - \U0001F5D1" if self.likes == 0 else ""

    @abstractmethod
    def play(self):
        print("Implement this method in a subclass.")
        raise NotImplementedError("Subclass must implement abstract method")

    @property
    @abstractmethod
    def description(self):
        print("Implement this method in a subclass.")
        raise NotImplementedError("Subclass must implement abstract method")


class Movie(Watchable):

    def __init__(self, name, year, length):
        super().__init__(name, year)
        self.length = length

    def __str__(self):
        trash = self._add_trashcan_icon()
        return f"{self.name} ({self.year}) - {self.length} min - {self.likes} likes{trash}"

    def play(self):
        print(f"Playing movie: {self.name} ({self.year})")

    @property
    def description(self):
        return f"This movie is called {self.name} and it's {self.length} minutes long."


class Series(Watchable):

    def __init__(self, name, year, seasons):
        super().__init__(name, year)
        self.seasons = seasons

    def __str__(self):
        formatted_seasons = SmallNumberFormatter.format_small_numbers(
            self.seasons)
        trash = self._add_trashcan_icon()
        return f"{self.name} ({self.year}) - {formatted_seasons} seasons - {self.likes} likes{trash}"

    def play(self):
        print(f"Playing series: {self.name} ({self.year})")

    @property
    def description(self):
        return f"This series is called {self.name} and it ran for {SmallNumberFormatter.format_small_numbers(self.seasons)} seasons."


class Playlist:

    def __init__(self, name, items):
        self.name = name
        self.items = items

    def __str__(self):
        formatted_size = SmallNumberFormatter.format_small_numbers(
            len(self.items) if len(self.items) >= 10 else len(self.items))
        playlist_str = f"Here's your {self.name} playlist with {formatted_size} items total:\n"
        for index, item in enumerate(self.items):
            playlist_str += f"{index + 1}) {item} ({item.id})\n"
        return playlist_str

    def __getitem__(self, item):
        return self.items[item]

    def __contains__(self, item):
        return item in self.items

    def __len__(self):
        return len(self.items)

    def average_likes(self):
        return sum(item.likes for item in self.items) / len(self.items) if len(
            self.items) > 0 else 0

    def total_movie_runtime(self):
        return sum(item.length for item in self.items
                   if isinstance(item, Movie))


class SmallNumberFormatter:
    WORDS = {
        number: word
        for number, word in enumerate(
            'zero one two three four five six seven eight nine ten'.split(), 0)
    }

    @staticmethod
    def format_small_numbers(number):
        return SmallNumberFormatter.WORDS.get(number, str(number))
2 respostas

Segue meu papo com o GPT ao longo deste curso. Bem pro final ele explicou o que são classes abstratas. Fez bastante sentido. Ei-lo.

Olá Rafael! Tudo bem?

Peço desculpa pela demora em responder o sue tópico.

Agradeço por compartilhar a sua implementação do exercício proposto pelo instrutor, a sua estrutura está boa e seguindo as boas práticas. Continue assim!

E sobre o seu papo com o GPT, o link que você compartilhou está quebrado, imagino que você tenha apagado o chat que você usou para que ele explicasse as classes abstratas.

Caso durante os seus estudos você tenha dúvidas ou problemas, você pode recorrer ao fórum. Contamos com uma grande comunidade que pode lhe ajudar.

Grande abraço e bons estudos!