I agree with you, so I'm going to ignore def branch2(a, b, z): and def branch3(a, b, z) because they appear too contrived - and I guess that's fair, in that you've contrived to satisfy pylint.

Question: are there other people/factors who/which should be regarded as more important than the linter's opinion?

The usual dictionary-controlled construct I've seen (and used) involves using functions as the dict's values:

def branch1( *args): pass
...
alternative[ x ] = branch1

and thus:

alternative[ choice ]( *args )


On 10/12/19 12:27 AM, Musbur wrote:
I have a function with a long if/elif chain that sets a couple of variables according to a bunch of test expressions, similar to function branch1() below. I never liked that approach much because it is clumsy and repetetive, and pylint thinks so as well. I've come up with two alternatives which I believe are less efficient due to the reasons given in the respective docstrings. Does anybody have a better idea?

def branch1(a, b, z):
     """Inelegant, unwieldy, and pylint complains
     about too many branches"""
     if a > 4 and b == 0:
         result = "first"
     elif len(z) < 2:
         result = "second"
     elif b + a == 10:
         result = "third"
     return result

Is it ironic that the language does not have a form of case/switch statement (despite many pleas and attempts to add it), yet the linter objects to an if-elif-else nesting???


One reason why this code looks a bit strange (and possibly why PyLint reacts?) is because it is trivial. When we look at the overall picture, the question becomes: what will the 'mainline' do with "result" (the returned value)? Immediately one suspects it will be fed into another decision, eg:

        if result == "first": # do the first-thing...
        if result == "second": # do the second-thing...

When found 'in real life', the above structure with such decisions is almost certainly followed by a second decision to select which 'action(s)' will be carried-out. The original-code rarely stands-alone, because all we've achieved is a labelling of the circumstances according to the arguments provided.


Rather than using a variable for 'labelling', (all other things being equal) I'd prefer to go straight to a function which 'does the business' - and use the function's name as a documenting 'label'!


A quick reflection shows that I have vacillated between two approaches:

1 put the decision-making in the 'mainline' and call a variety of functions/methods to do 'the first thing' etc. ie more-or-less what you have here, except the cascade of decisions is not separated from 'what came before'.

def calculation( value, operator, operand):
        if operator == "+":
                add( value, operand)
        elif operator == "-":
                sub( value, operand)


2 arrange/call a series of functions each dealing with a single circumstance, eg (borrowing from @Chris) should I "tap"?. Thus each function will firstly check if the circumstances demand that action, ie the applicable one of the if-clauses above, and if they do, then implement that action: 'do the first thing' (etc).

value = handle_add( value, operator, operand )
value = handle_sub( value, operator, operand )

where:

def handle_add( value, operator, operand):
        if operator == "+":
                return value + operand
        return value

Ugh - the example is no less contrived and grossly artificial...


The second of those appears somewhat 'cleaner' - in that we have 'hidden away' all those pesky if-constructs; BUT it is NOT immediately obvious exactly how many of the series of functions will actually result in any 'action' (if not, all of them). So, perhaps that raises the (earlier/elsewhere) question of whether the various action-functions are dependent or independent/exclusive of each other? It also requires carefully choosing descriptive function names!
--
Regards =dn
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to