Home > database >  python decorators property: getter/setter
python decorators property: getter/setter

Time:06-14

I have this code that I'm trying to use decorators getters and setters to append a simple list that receives data from an API. However the list is coming empty, I've tried out a lot of examples but I just cant seem to get it right.

import requests
from typing import Dict, List

headers_ = {
    'sm-token': '{"Location":{"Latitude":-23.551548099999998,"Longitude":-46.6331008},"IdClientAddress":0,"IsDelivery":false,"IdLoja":2691,"IdRede":884,"DateBuild":"2022-06-08T00:09:36.738357"}',
}

class Scraper:
    def __init__(self):
        self.session = requests.Session()
        self.header = {'sm-token': '{"Location":{"Latitude":-23.551548099999998,"Longitude":-46.6331008},'
                                   '"IdClientAddress":0,"IsDelivery":false,"IdLoja":2691,"IdRede":884,"DateBuild":'
                                   '"2022-06-08T00:09:36.738357"}'}
        self.category_list = ['bebidas', 'bebidas-alcoolicas']
        self.market_id = [2691]
        self.sub_categ_list = []

    def sub_categories(self) -> List:
        url_sub_categ = (f'https://b2c-api-premiumlabel-production.azurewebsites.net/api/b2c/page/'
                         f'menu?id_loja={self.market_id[0]}')

        for dep in self.session.get(url_sub_categ, headers=self.header).json()['departments']:  # ['departments']
            self.sub_categ_list.append((dep['imagem_url'], dep['categories']))  # self.sub_categ_list  # sub_categ_list

    # def aaa(self):
    #     ab = self.sub_categories()
    #     return ab

    @property
    def sub_categ_list(self):
        print('getter')
        return self._sub_categ_list

    @sub_categ_list.setter
    def sub_categ_list(self, valor):
        valor = [str(x).replace('4', '40') for x in valor]
        print('setter')
        self._sub_categ_list = valor

scrape = Scraper()
# print(scrape.sub_categories())  # original function OK
print(scrape.sub_categ_list)  # decorator value empty
# print(scrape.aaa())  # function called directly, I heard that it is not a good practice

If you uncomment the line with function "def aaa(self)" and print it, you're gonna see this one works (as the well the original function also works), but I don't want to call the function directly from another function such as "aaa".

Obs: I have knowledge until functions, never tried out classes or decorators, I'm building my first OOP project, so ANY advice or changes to the code are very welcome, I just want to start learning the right way to do OOP.

The purpose of this project is retrieving data from API, some data cleanings, creating data frame with pandas and store it somewhere.

CodePudding user response:

The __init__ function sets the property to []. So just creating scape = Scraper() will only generate an empty list. Printing the property after that returns the empty list as expected.

If you want to populate the list on creation, use the following in __init__:

self.sub_categ_list = self.sub_categories()

Then change the sub_categories function to return the populated list so it is assigned to the property:

    def sub_categories(self) -> List:
        url_sub_categ = (f'https://b2c-api-premiumlabel-production.azurewebsites.net/api/b2c/page/'
                         f'menu?id_loja={self.market_id[0]}')

        result = []
        for dep in self.session.get(url_sub_categ, headers=self.header).json()['departments']:  # ['departments']
            result.append((dep['imagem_url'], dep['categories']))  # self.sub_categ_list  # sub_categ_list
        return result

Also, a note about the "right way to do OOP". Returning an internal mutable member variable of the class instance isn't a good idea. Doing something like the following inadvertently modified the internal s._sub_categ_list list as well, because x is a reference to the same list.

s = Scraper()
x = s.sub_categ_list
x.append(5)

You're better off calling s.sub_categories() where it returns a new list each time like I've defined it above.

  • Related