3 ms·
If actions are different, I tend to put them in functions (independent testable pieces, yay!) and iterate over a mapping: LINE_ACTIONS = ( (re.comp
by drdaeman 7y ago
If actions are different, I tend to put them in functions (independent testable pieces, yay!) and iterate over a mapping:
LINE_ACTIONS = (
(re.compile("pattern 1"), do_stuff),
(re.compile("pattern 2"), do_other_stuff),
(re.compile("pattern 3"), do_something_else),
)
...
for pattern, action in LINE_ACTIONS:
m = pattern.search(line)
if m is not None:
action(m)
break
Or even use a method registry pattern that would auto-populate LINE_ACTIONS by just declaring the fuctions:
@action("pattern 1")
def do_stuff(m):
...
Alternatively, I might just break the processing into a function:
def _process(line):
m = pat1.search(line)
if m is not None:
... do stuff ...
return
m = pat2.search(line)
if m is not None:
... do stuff ...
return
m = pat3.search(line)
if m is not None:
... do stuff ...
return
_process(line)
Of course, this depends on the purpose. Could be completely inadequate in some situations.
- eesmith 7y agoIndeed, I've also used this pattern. I've found that I don't like using it. As you write, it's "inadequate in some situations", which I consider as part of the cumbersome complexities I mentioned. For examples, do_stuff() and do_other_stuff() may need to share variables, and do_something_else() might need the line number to report an error while the others don't. This can be handled with shared state/nonlocal, and by passing in more parameters to the generic handler API, but these add complexity. Or, different parts of the file may have different line dispatch processing (eg, a header block followed by a data block followed by a footer block) where one of the handlers must indicate the transition to a different processor. Also, function dispatch in CPython is slow. While the regex tests are also slow, it can also be important to consider the (using a hypothetical number) 5% overhead for dispatching over inline code.