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.