Home > database >  Creating instances of a function via a configuration file
Creating instances of a function via a configuration file

Time:03-09

We have a configuration file that is read and stored as a dictionary, e.g.

config = {'type': A, 'input': {'color': 'red', 'border': 'thick', 'shape': 'square'}}

Now we want to use this config object to create an instance of a class, say, Drawing_Class with the condition that if the type is 'A', the colour is always blue, and if the type is 'B' the shape is always a circle.

I have written a function to achieve this which seems very unpythonic, and was wondering if there is a better way to achieve my goal? Of course, in the example I've given one could just input the desired colour and shape in the configuration file, but the actual problem is more complex and that can't be achieved.

Here is my function.

def drawing_dictionary(type):
    if type == 'A':
        value = config['inputs'].pop('color')
        output = drawing_function(**config['inputs'], colour='blue')
        config['input']['color'] = value

    if type == 'B':
        value = config['inputs'].pop('shape')
        output = drawing_function(**config['inputs'], shape='circle')
        config['input']['shape'] = value

    return output

It achieves what I need it to achieve, i.e. creating custom instances based on this configuration file, but in a way that seems very inelegant. Help would be much appreciated.

CodePudding user response:

I asked a question about drawing_function but figured I'd put some things down in an answer and update as necessary.

First off do not name a variable type as while it isn't a reserved keyword in python it is a built in function that allows you to determine the type of an object.

Second you say you want to create an instance of a function, are you talking about a functor? Is drawing_function a class? or are you just calling a function with different arguments depending on a config file (this is what your code seems to indicate and what I have assumed)?

The other code in your project will have an impact on the argument list you want to use and how you want to move data around so that the function gets the correct arguments. Your example code looks like you've made config a global variable which I would not recommend.

What if the config file has extra values in it or is missing values? You'd cause an exception I've added a theoretical validation routine.

Some recommended changes to your example code:

def drawing_dictionary(config):
    config = validate_config(config) #remove values you don't understand
    #and confirm all the values you need are present set type to 'Error' 
    #if something is wrong
    if config['type'] == 'Error':
        handle_error()#maybe set a default config?
    else: #this assumes you can't fix the config
        return drawing_function(**config['inputs'],config_type=config['type'])

    return some_sort_of_error_value_or_throw_exception

inside of drawing_function you will have all the values in the config['inputs'] unpacked so you'll have a variable named colour and one names shape then you can handle the changes by type in that function to ensure it always happens and without changing the config dictionary:

if config_type == 'A':
    colour = 'blue'
elif config_type == 'B':
    shape = 'circle'

You could also swap out the if elif stuff for a match case statement if you're using python 3.10 or newer.

CodePudding user response:

I like to use dicts to take the place of potentially-large if-elif blocks, so the first thing I would do is to create a lookup for the type names, containing the field name and default value for each type.

types = {
    "A": ("color", "blue"),
    "B": ("shape", "circle"),
}

I would also recommend copying the contents of the config table, rather than modifying it. This will keep you from accidentally modifying it, and also makes the function re-entrant. Here's my version:

def drawing_dictionary(typename):
    key, default = types[typename]
    kwargs = config["inputs"].copy()
    kwargs[key] = default
    return drawing_function(**kwargs)

With this implementation, supporting a new type is as simple as adding a row in types, rather than defining a new if block.

  • Related