I have a function that should allow filtering the users to be uploaded to a list, the problem is that the filters (parameters) should be optional. I didn't find a way to ignore filters with value None
. The following code is a situation similar to what I want to do, so you can run and test.
def get_participants(name=None, email=None, rol=None):
# obtengo el listado
trs = [
{'name': 'ramon juanes', 'email': '[email protected]', 'rol': 'jefe'},
{'name': 'lara galaz', 'email': '[email protected]', 'rol': 'trabajador'},
{'name': 'samuel adobe', 'email': '[email protected]', 'rol': 'trabajador'},
{'name': 'juan carlos', 'email': '[email protected]', 'rol': 'supervisor'},
]
participants = []
for tr in trs:
user = Participant(tr)
# momento del filtro
# si un filtro es None produce un TypeError
# if name in user.name and email in user.name and rol in user.rol:
# participants.append(user)
# si un filtro es None no toma en cuenta al resto de los campos
# if (name and name in user.name) and (email and email in user.name) and (rol and rol in user.rol):
# participants.append(user)
# este caso no tiene sentido tomarlo debido al siguiente resultado:
# len(get_participants(name='lara', email='minum')) -> 2, pero debería ser 0, ya que no esta en listado
# if (name and name in user.name) or (email and email in user.name) or (rol and rol in user.rol):
# participants.append(user)
return participants
class Participant:
def __init__(self, tr):
self.name = tr['name']
self.email = tr['email']
self.rol = tr['rol']
In the original code:
def get_participants(self, subject_id, name=None, email=None, rol=None):
self.open_with_session(f'https://www.page.com/user/index.php?id={subject_id}')
trs = self.page.select('#participants tbody tr')
participants = []
for tr in trs:
user = Participant(tr)
# TypeError cuando name, email o rol es None
if name in user.name and email in user.name and rol in user.rol:
participants.append(user)
return participants
class Participant:
def __init__(self, tr):
self.name = tr.select_one('.c1').text.lower()
self.email = tr.select_one('.c2').text.lower()
self.rol = tr.select_one('.c3').text.strip().lower()
I've tried using the argument **kwargs
but that would mean turning my objects Participant
into dictionaries, and using a for
with a break
, which takes some of the elegance out of the code:
def get_participants(**kwargs):
# obtengo el listado
trs = [
{'name': 'ramon juanes', 'email': '[email protected]', 'rol': 'jefe'},
{'name': 'lara galaz', 'email': '[email protected]', 'rol': 'trabajador'},
{'name': 'samuel adobe', 'email': '[email protected]', 'rol': 'trabajador'},
{'name': 'juan carlos', 'email': '[email protected]', 'rol': 'supervisor'},
]
participants = []
for tr in trs:
user = {
'name': tr['name'], # tr.select_one('.c1').text.lower()
'email': tr['email'], # tr.select_one('.c2').text.lower()
'rol': tr['rol'], # tr.select_one('.c3').text.strip().lower()
}
append = True
for key in kwargs.keys():
if not kwargs[key] in user[key]:
append = False
break
if append:
participants.append(user)
return participants
This code works, but I would like to know if there is a simpler way to accomplish this task and without having to use dictionaries (replacing my objects Participant
).
From already thank you very much.
To filter the participants, two conditions can be taken into account:
Then we can use the following conditions:
Note that by short circuit if name is None ,
name in user.name
it is not evaluated and therefore does not throw an exception.And to exemplify the possible cases, a kind of "truth table" of name_match :