I have around 20 functions开发者_运维知识库 (is_func1, is_fucn2, is_func3...) returning boolean
I assume there is only one function which returns true and I want that!
I am doing:
if is_func1(param1, param2):
# I pass 1 to following
abc(1) # I pass 1
some_list.append(1)
elif is_func2(param1, param2):
# I pass 2 to following
abc(2) # I pass 1
some_list.append(2)
...
.
.
elif is_func20(param1, param2):
...
Please note: param1 and param2 are different for each, abc and some_list take parameters depending on the function.
The code looks big and there is repetition in calling abc and some_list, I can pull this login in a function! but is there any other cleaner solution?
I can think of putting functions in a data structure and loop to call them.
What about
functionList = [is_func1, is_func2, ..., is_func20]
for index, func in enumerate(functionList):
if(func(param1, param2)):
abc(index+1)
some_list.append(index+1)
break
I can think of putting functions in a data structure and loop to call them.
Yes, probably you should do that since your code needs to be refactored,
and a data driven design is a good choice.
An example similar to BlueRaja's answer,
# arg1, arg2 and ret can have any values on each record
data = ((isfunc1, arg1, arg2, ret),
(isfunc2, arg1, arg2, ret),
(isfunc3, arg1, arg2, ret),
...)
for d in data:
if d[0](d[1], d[2]):
abc(d[3])
some_list.append(d[3])
break
If each branch of your event dispatcher is in fact different, then there just isn't any way to get around writing the individual branch handlers, and there isn't any way to get around polling the different cases and choosing a branch.
This looks a good case to apply Chain of responsibility pattern.
I know how to give the example with objects, not functions, so I'll do that:
class HandleWithFunc1
def __init__(self, otherHandler):
self.otherHandler = otherHandler
def Handle(param1, param2):
if ( should I handle with func1? ):
#Handle with func1
return
if otherHandler == None:
raise "Nobody handled the call!"
otherHandler.Handle(param1, param2)
class HandleWithFunc2:
def __init__(self, otherHandler):
self.otherHandler = otherHandler
def Handle(param1, param2):
if ( should I handle with func1? ):
#Handle with func1
return
if otherHandler == None:
raise "Nobody handled the call!"
otherHandler.Handle(param1, param2)
So you create all your classes like a chain:
handle = HandleWithFunc1(HandleWithFunc2())
then:
handle.Handle(param1, param2)
This code is prone to refactoring, here only to illustrate the usage
Try this:
value = 1 if is_func1(param1, param2) else \
2 if is_func2(param1x, param2x) else \
... else \
20 if is_func20(param1z, param2z) else 0
abc(value)
some_list.append(value)
Bear in mind that this statement was cobbled together using various websites as a reference for Python syntax, so please don't shoot me if it doesn't compile.
The basic gist is to produce a single value that corresponds to the function called (1 for is_func1
, 2 for is_func2
, etc.) then use that value in the abc
and some_list.append
functions. Going on what I was able to read about Python boolean expression evaluation, this should properly short-circuit the evaluation so that the functions stop being called as soon as one evaluates to true.
I modified BlueRaja answer for different parameters...
function_list = {is_func01: (pa1, pa2, ...),
is_func02: (pa1, pa2, pa3, ...),
....
is_func20: (pa1, ...)}
for func, pa_list in function_list.items:
if(func(*pa_list)):
abc(pa_list_dependent_parameters)
some_list.append(pa_list_dependent_parameters)
break
I don't see why it shouldn't work.
I've not used python before, but can you refer to functions by a variable?
If so, you can create an enum with entries representing each function, test all the functions in a loop, and set a variable to the 'true' function's enum.
Then you can do a switch statement on the enum.
Still, that won't 'clean up' the code much: when you have n options and need to drive down to the correct one, you'll need n blocks of code to handle it.
I'm not sure if it would be cleaner, but I think is's quite interesting solution.
First of all you should define new function, let it be semi_func
, which will call abc
and some_list.append
do make code DRY.
Then set new variable to act as a binary result of all boolean functions, so the is_func1 is 20th bit of it, is_func2 is 19th and so on. 32 bits of integer type should be enough to handle all 20 results.
While setting value to this result variable you should use shift left to add new functions:
result = is_func1(param1, param2) << 1
result = (result | is_func2(param1, param2)) << 1
...
result = (result | is_func20(param1, param2))
For ease access define new constants like
IS_FUNC20_TRUE = 1
IS_FUNC19_TRUE = 2
IS_FUNC18_TRUE = 4
... values should be powers of 2
And in the end use switch/sase statement to call semi_func
.
I know I will be modded down for being offtopic, but still. If you find anything that can be done with standard control constructs off-putting, then you need to use a different language, such as Common Lisp, which allows for macros, in effect makes it possible to create your own control constructs. (Having recently discovered anaphoric macros, I just have to recommend this.)
This specific case would be a perfect example where a macro would help, but only assuming you are doing it at multiple places in your code, otherwise it's probably not worth improving at all. And in fact, Common Lisp already has a macro like that, it's called cond.
Anyway, in Python, I think you should go along with a list of functions and a loop.
精彩评论