I have a config.py file which as a bunch of bool parameters like
show_timer = True
display_graph = True
My main code runs in a while loop, and the loop seems very cluttered with code that is not executed if the above parameters are False. What is the best approach for readability for this kind of configuration file driven codes? I am currently using a format like:
init_someting() if display_graph else None
while True:
do_something() if show_timer else None
.
.
.
As Martijn said in his comment, don't use a conditional expression; use a normal if statement. It seems like you've got all the actions in functions already, so I don't think there's much else to do.
if display_graph:
init_something()
while True:
if show_timer:
do_something()
if other_option:
do_other_thing()
For Educational Purposes Only (but there are places where this pattern is useful)
Depending on the details of what you're doing, you could also use the config options to build a list of functions to be called, then loop repeatedly over that. Something like this:
if display_graph:
init_something()
functions_to_call = []
if show_timer:
functions_to_call.append(do_something)
if other_option:
functions_to_call.append(do_other_thing)
while True:
for function in functions_to_call:
function()
Or:
if display_graph:
init_something()
all_functions = [
(show_timer, do_something),
(other_option, do_other_thing),
]
functions_to_call = [function for (flag, function) in all_functions if flag]
while True:
for function in functions_to_call:
function()
/For Educational Purposes Only
If keeping additional objects is not a constraint, you can have a dict with config to function mapping.
func_dict = {'show_timer': timer_func,
'display_graph': display_graph_func}
Now iterate over func_dict to check config values. Something like:-
for config_param, func_obj in func_dict.items():
if config[config_param]:
func_obj()
or in shorthand:-
[func_obj() for config_param, func_obj in func_dict.items() if config[config_param]
But again passing parameters to functions will be an issue. Check if you can work out on it.
Related
I wrote a simple command-line tool in Python. To simplify the logic, I use a dict for storing the commands and handlers, something like this:
#!/usr/bin/env python
# some code here
DISPACHERS = {
"run": func_run
"list": func_list
}
# other code
The problem is, I have to put this piece of code after the function declarations, which is not the standard practice I have seen in other languages (i.e. constants in one block, variables after, and then the functions).
I could use strings for storing the function, and retrieve it using something like getattr(__main__, "func_run"), so I can stick with my preference, but I wonder if that's a "proper" way.
Any idea?
=== Update ===
Since it's a simple python script that handles some automation tasks of another project, so it would be better to keep it in a single file (no other module) if possible.
Use a decorator to enumerate the functions.
dispatchmap = {}
def dispatcher(name):
def add_dispatcher(func):
dispatchmap[name] = func
return func
return add_dispatcher
...
#dispatcher('run')
def func_run(...):
...
I have some topic to discuss. I have a fragment of code with 24 ifs/elifs. Operation is my own class that represents functionality similar to Enum. Here is a fragment of code:
if operation == Operation.START:
strategy = strategy_objects.StartObject()
elif operation == Operation.STOP:
strategy = strategy_objects.StopObject()
elif operation == Operation.STATUS:
strategy = strategy_objects.StatusObject()
(...)
I have concerns from readability point of view. Is is better to change it into 24 classes and use polymorphism? I am not convinced that it will make my code maintainable... From one hand those ifs are pretty clear and it shouldn't be hard to follow, on the other hand there are too many ifs.
My question is rather general, however I'm writing code in Python so I cannot use constructions like switch.
What do you think?
UPDATE:
One important thing is that StartObject(), StopObject() and StatusObject() are constructors and I wanted to assign an object to strategy reference.
You could possibly use a dictionary. Dictionaries store references, which means functions are perfectly viable to use, like so:
operationFuncs = {
Operation.START: strategy_objects.StartObject
Operation.STOP: strategy_objects.StopObject
Operation.STATUS: strategy_objects.StatusObject
(...)
}
It's good to have a default operation just in case, so when you run it use a try except and handle the exception (ie. the equivalent of your else clause)
try:
strategy = operationFuncs[operation]()
except KeyError:
strategy = strategy_objects.DefaultObject()
Alternatively use a dictionary's get method, which allows you to specify a default if the key you provide isn't found.
strategy = operationFuncs.get(operation(), DefaultObject())
Note that you don't include the parentheses when storing them in the dictionary, you just use them when calling your dictionary. Also this requires that Operation.START be hashable, but that should be the case since you described it as a class similar to an ENUM.
Python's equivalent to a switch statement is to use a dictionary. Essentially you can store the keys like you would the cases and the values are what would be called for that particular case. Because functions are objects in Python you can store those as the dictionary values:
operation_dispatcher = {
Operation.START: strategy_objects.StartObject,
Operation.STOP: strategy_objects.StopObject,
}
Which can then be used as follows:
try:
strategy = operation_dispatcher[operation] #fetch the strategy
except KeyError:
strategy = default #this deals with the else-case (if you have one)
strategy() #call if needed
Or more concisely:
strategy = operation_dispatcher.get(operation, default)
strategy() #call if needed
This can potentially scale a lot better than having a mess of if-else statements. Note that if you don't have an else case to deal with you can just use the dictionary directly with operation_dispatcher[operation].
You could try something like this.
For instance:
def chooseStrategy(op):
return {
Operation.START: strategy_objects.StartObject
Operation.STOP: strategy_objects.StopObject
}.get(op, strategy_objects.DefaultValue)
Call it like this
strategy = chooseStrategy(operation)()
This method has the benefit of providing a default value (like a final else statement). Of course, if you only need to use this decision logic in one place in your code, you can always use strategy = dictionary.get(op, default) without the function.
Starting from python 3.10
match i:
case 1:
print("First case")
case 2:
print("Second case")
case _:
print("Didn't match a case")
https://pakstech.com/blog/python-switch-case/
You can use some introspection with getattr:
strategy = getattr(strategy_objects, "%sObject" % operation.capitalize())()
Let's say the operation is "STATUS", it will be capitalized as "Status", then prepended to "Object", giving "StatusObject". The StatusObject method will then be called on the strategy_objects, failing catastrophically if this attribute doesn't exist, or if it's not callable. :) (I.e. add error handling.)
The dictionary solution is probably more flexible though.
If the Operation.START, etc are hashable, you can use dictionary with keys as the condition and the values as the functions to call, example -
d = {Operation.START: strategy_objects.StartObject ,
Operation.STOP: strategy_objects.StopObject,
Operation.STATUS: strategy_objects.StatusObject}
And then you can do this dictionary lookup and call the function , Example -
d[operation]()
Here is a bastardized switch/case done using dictionaries:
For example:
# define the function blocks
def start():
strategy = strategy_objects.StartObject()
def stop():
strategy = strategy_objects.StopObject()
def status():
strategy = strategy_objects.StatusObject()
# map the inputs to the function blocks
options = {"start" : start,
"stop" : stop,
"status" : status,
}
Then the equivalent switch block is invoked:
options["string"]()
I have router that is deciding which function to call based upon user input (uses ConfigParser) and then tries to decide which function to call.
def SomethingElse():
print 'hello'
def UploadDirectory():
print 'hi'
def router(config):
if config.has_option('job', 'Some_Task'):
taskName = config.get('job', 'Some_Task')
# taskName is now 'UploadDirectory'
###execute the UploadDirectory function
###execute something else if something else, etc
So what is the way to write this in python? If I prebuilt a map of functions to strings, can i execute them that way?
How would you write this?
Yep, building a map of strings to function names is perfectly valid:
task_map = {
'upload': UploadDirectory,
'something': SomethingElse,
}
And execute as:
task_map[task_name]()
Aside: try to follow PEP-8, the python style guide; it helps make your code more readable to all other Python programmers. Specifically in this case, prefer underscore_separated function names instead of LeadingCaps.
Another hacky way to do it is to use globals(), if you're not running just by importing the router function:
globals()[taskName]()
I wonder how to correctly use python 2.7 callback functions.
I have some callback functions from Cherrypy auth examples in my code.
(These callbacks return a function that can evaluate to True or False, depending on the logged in user being in a group or not.)
I wonder if a callback is executed or not if I write a piece of code like this:
Given the definition from the library is:
def member_of(groupname):
def check():
if groupname == 'admin':
if cherrypy.request.login == 'joe':
return True
if cherrypy.request.login == 'toni':
return True
return False
return False
# .... (other groups checked in the same way)
return check # returns a callback function from my understanding?
How can I apply and execute the callback in my code?
If I put it like this:
if member_of('admin'):
do_something()
else:
do_something_else()
Will this execute the calllback and check for the admin group? Or will it find out if the value of "member_of" is a function definition and a function definition is probably always a "True" value (or maybe a False value) but both are wrong, because it needs to be executed
Can you enlighten me on this? How can I make sure a callback is executed? An how can I pass it around as it is?
In python, like in many other languages, a variable can also contain a function and you can pass them around like other variables that contain e.g. numbers or strings.
CherryPy's member_of function itself does return a function in your example.
I am explaining it in simple steps:
If you write member_of() it returns the result of the function member_of() which is the function with the name check in this case.
cb_function = member_of('admin')
At this point the variable cb_function holds the result of calling the function member_of, and in the last line member_of returns check, which was defined within the function member_of as another function!
You have to call the first result again, because you can and you have to treat it in almost the same way as a local function, that you defined in the current context, to get the final result, by doing something like:
my_result = cb_function()
And then you would continue and use the result. For example you could check its boolean value:
if my_result:
# do something
...
The 3 steps from above together can be written shorter:
cb_function = member_of('admin')
if cb_function():
# do something
...
Or even shorter:
if member_of('admin')():
# do something
...
At first it may appear a little strange in python to have the double ()(), but if you think about it for a while it makes sense.
If you execute it, it is plain simple.
member_of() will return method object check.
you have to execute to get result by doing something like if member_of('admin')():
or,
k=member_of('admin')
if k():
To do your task.
HI !
I guess everything is in the question ...
I was just wondering if there is a nice way in Python to shorten this pattern :
something = get_something()
if something:
do_a_thing_with(something)
Meaning that I would like to enter in the if context only if the variable something is not None (or False), and then in this context having this variable set automatically ! Is it possible with with statement ?
PS : I don't want to have to DEFINE more stuff... I am looking for some statement to use on the fly ?!
This is as pythonic as it gets.
Things should be no more simplified than they are and no more complex than they should be.
See how the with statement works and providing a context guard. would be complicated enough.
http://effbot.org/pyref/with.htm
http://effbot.org/pyref/context-managers.htm
If it is a pattern that is very frequent in your code (as you suggested in a comment to #pyfunc's answer), you can just make it a function:
def safeProcessData(getData, handleData):
buffer = getData()
if buffer:
handleData(buffer)
In this case the parameters getData and handleData would be callables, meaning any function (free or member) and objects that implement __call__.
As others have said, your existing code is already nice and short... If you really want a one-liner, try a list comprehension:
[do_a_thing_with(something) for something in [get_something()] if something]