0

This is really a code layout/design question. Forgive me if it's a little vague -- happy to clarify anything.

I have a ~400 line Python program (3 files) that has functions that generate "primitive" objects (smaller atomic objects), functions that call those functions to build up slightly more complex objects using those atomic ones...and then functions that call those that build final (larger / more complex) objects.

The reason I'm questioning the program's design is each function takes a lot of arguments (10-15) and I have to pass them through the the whole stack each time. It makes the code seem a lot longer and probably messier than it needs to be, I'm guessing.

What's the best way to consolidate this? Some use of *args and **kwargs?

Currently the whole program is functional and I've considered making it object-oriented but I haven't decided if that would actually improve this.

Here is a snippet of code that shows the args passing through the stack:

def gen_tag(tag_key_size, tag_value_size, key=''):
    # return string Tag key-value pair
    if key:
        held_key = 'tag_' + key
        held_key = held_key[:-4]
        val = _gen_string(tag_value_size)
        pair = f",{held_key}={val}"
    else:
        key = 'tag_' + _gen_string((tag_key_size-4))
        val = _gen_string(tag_value_size)
        pair = f",{key}={val}"

    return(pair)

def gen_tagset(num_tags, tag_key_size, tag_value_size, tag_keys):
    if tag_keys:
        tagset = ''.join(primitives.gen_tag(tag_key_size,tag_value_size, key=i) for i in tag_keys) + ' ' 
    else:
        tagset = ''.join(primitives.gen_tag(tag_key_size,tag_value_size) for i in range(num_tags)) + ' '
    
    return(tagset[1:])

def gen_line(measurement,
                num_tags,
                int_fields,
                float_fields,
                str_fields,
                tag_key_size,
                tag_value_size,
                field_key_size,
                int_value_size,
                float_value_size,
                str_value_size,
                precision,
                tag_keys,
                int_field_keys,
                float_field_keys,
                str_field_keys):


    tagset = sets.gen_tagset(num_tags, tag_key_size, tag_value_size, tag_keys)
    fieldset = sets.gen_fieldset(int_fields, float_fields, str_fields, field_key_size, int_value_size, float_value_size, str_value_size, int_field_keys, float_field_keys, str_field_keys)
    timestamp = primitives.gen_ts(precision)
    line = f"{measurement},{tagset}{fieldset}{timestamp}"

    return(line)

From there, I have a function that calls gen_tagset(<args>) and then another function that builds from that...each time getting passed a long list of similar arguments.

Sam Dillard
  • 670
  • 1
  • 5
  • 18
  • 1
    `**kwargs` is what a lot of libraries use. It makes writing the code easier, but if it isn't documented well, it becomes a mess to use. All the "top-level" functions just have `**kwargs` in their signature, which isn't helpful at all. – Carcigenicate Nov 05 '20 at 22:40
  • @Carcigenicate so is it fair that I've laid this out this way? I'm not an experienced programmer so I could be missing something really obvious! – Sam Dillard Nov 05 '20 at 22:42
  • 1
    I use explicit parameters on each function in the "chain" for small amounts of parameters, but that of course has its own downsides. At 10-15 parameters though, grouping the data in someway would probably needed, since any change would need to be reflected everywhere. If the data makes sense together, and the data that's grouped is consistent, a `dataclass` or `NamedTuple` may be a good option. If you're willing to document the parameters, `kwargs` may be the way to go too. – Carcigenicate Nov 05 '20 at 22:46
  • 1
    [Related discussion for Java](https://stackoverflow.com/questions/2432443/best-practice-for-passing-many-arguments-to-method), and [another for C++](https://stackoverflow.com/questions/24952190/elegant-way-to-pass-multiple-arguments-to-a-function). Obviously not directly relevant, but a lot of what's discussed applies to Python as well. – Carcigenicate Nov 05 '20 at 22:53

0 Answers0