Reputation: 21188
I'm writing a method that will filter records by called conditions. What I mean, is it will check if default conditions are met for any record and then if specified, checks if additional conditions needs to be met for those records. But if those conditions are not specified, it will just ignore it.
So I could write it like this:
def test_conditions(a, b=None)
#b - this one is additional condition that might be specified or not
if a > 5 and (b > 10 if b else True):
print 'record passed'
It is working I need to, but I don't think it looks very elegant and I will need to use more than one additional condition that might or might not be specified when method is called and then such method might not look good.
So maybe there is some practice in Python how to best solve such problems (I mean best way to handle those additional conditions when you don't know if you will need to check it or not before method is called)?
I was asked to provide real code I was writing, so here it is:
def countEmergency(self, card_ids, duration=None):
cnt = 0
for card in card_ids:
if card.emergency_level == 'first' and (card.duration > duration if duration else True):
cnt += 1
return cnt
Upvotes: 1
Views: 262
Reputation: 122150
Rather than print
I would return
either True
or False
, then you can check each item individually. Assuming that you're testing the attributes on some object (but this can be adapted to whatever you need):
def test_conditions(obj, a=5, b=None):
if obj.a <= a:
return False
if b is not None and obj.b <= b:
return False
return True
Alternatively, use **kwargs
to take arbitrary keyword arguments:
def test_conditions(obj, a=5, **kwargs):
if obj.a <= a:
return False
for k, v in kwargs.items():
if getattr(obj, k) <= v:
return False
return True
or
def test_conditions(obj, **kwargs):
if obj.a <= kwargs.get('a', 5):
return False
for k, v in kwargs.items():
if getattr(obj, k) <= v:
return False
return True
Given what you're actually doing, use continue
instead of returning:
def countEmergency(self, card_ids, duration=None):
cnt = 0
for card in card_ids:
if card.emergency_level != 'first':
continue
if duration is not None and card.duration <= duration:
continue
cnt += 1
return cnt
Alternatively, refactor to use a function as above, that takes one card
, and use filter
to get a list of valid elements from card_ids
.
from functools import partial
class WhateverThisIs(object):
...
@staticmethod
def validate_card(card, duration=None):
if card.emergency_level != 'first':
return False
if duration is not None and card.duration <= duration:
return False
return True
def countEmergency(self, card_ids, duration=None):
return len(filter(partial(self.validate_card, duration=duration), card_ids))
This uses functools.partial
to create an appropriate filtering function. Note that your countEmergency
doesn't use any instance or class attributes or methods - you should review whether it needs to be an instance method.
Upvotes: 3