Property or Dataclass

Working with an API response, I have 2 possible choices of handling the return and access but I’m lost on which one’s ideal:

# Example API Response
{
    'title': 'Blade Runner',
    'year': 1982
}

Option 1: property


class Movie:
    def __init__(self, search):
        self._search = search

    def api_response(self):
        response = requests.post(url)

    @property
    def title(self) -> str:
        return response["title"]

    @property
    def year(self) -> int:
        return response["year"]

Option 2: dataclass

@dataclass
class Movie:
    title: str
    year: int

class SearchMovie:
    def __init__(self, search):
        self._search = search

    def api_response(self):
        response = requests.post(url)
        return Movie(title=response["title"], year=response["year"])

There was a more detailed Stackoverflow post here but I couldn’t really gauge a conclusion from it

Almost always dataclass. And that SearchMovie class shouldn’t exists, at least not in it’s current form:

@dataclass
class Movie:
    title: str
    year: int

    @classmethod
    def from_api(cls, search):
        url = url_from_search(search)
        response = requests.post(url)
        return Movie(...)

Or, if you have a proper API manager class:

class API:
    def __init__(self, url=...):
        self.base_url = url
        self.session = requests.Session(...)

    def search_movie(self, search) -> Movie:
        response = self.session.post(self.build_url_for_search(search))
        return Movie(...)

In general: attributes for things, properties for computed things, methods for actions.

2 Likes

Thank you! Can you expand on the last bit?

In general: attributes for things, properties for computed things, methods for actions.

Properties look like attributes. They should not have side effects.
If something happens, it should look like a function/method call.

1 Like

The most obvious reason to reject Option 1 has nothing to do with properties or dataclasses, but the fact that Movie.api_response doesn’t use self at all. It should be a class method, a static method, or a standalone function (IMO, in increasing order of appropriateness).

Whether Movie exposes its title and year attributes publicly or via properties is an orthogonal question. The way properties work, you can start with a simple class (whether you use dataclasses.dataclass to help define that class is almost irrelevant), and later replace the instance attributes with properties without changing the public interface of the class.

1 Like