Preferred way of mutating dictionary inside function/method and returning to the caller?

Viewed 132

Well, wondering what is the suggested way (i.e. best practice) to pass some dictionary to function/method, modify it and "return" to the user?

For example, as dictionary is mutable, we can simply do:

my_dict = {
    'a': 'b'
}

def foo(bar):
    # Do something with `bar`...
    ...
    bar['c'] = d  # Update `bar`.

foo(my_dict)
# Do something with modified `my_dict`...

This is what I was doing mostly in the past.

But another, more explicit, way to get the same effect would be:

my_dict = {
    'a': 'b'
}

def foo(bar):
    # Do something with `bar`...
    ...
    bar['c'] = 'd'  # Update `bar`.
    return bar

my_dict = foo(my_dict)
# Do something with modified `my_dict`...

This maybe follows better one of the most important Python principles: "Explicit is better than implicit.", but definitely requires little more writing (maybe unnecessarily).

Of course, there are also other approaches to achieve the same, but wondering which is preferred way between above two?

P.S. This is my first question ever on StackOverflow (for 10+ years in programming)... I tried to search for similar use-cases (as always), but incredible that nobody ever asked.

EDIT: Updated examples to be more specific.

3 Answers

I'd say better to not return

Well look no further than list.sort()

It sorts list in-place, meaning original list changes, and nothing is returned.

The reason for returning None is so users do not get confused (thinking original list is preserved)

The most important thing is to properly name what you're doing
e.g.

def fill_with_defaults(cfg):
    ...

And then fill_with_defaults(configuration) is looking perfectly readable

And as for "explicit", no return value is even better because the reader knows something is changed in-place
meaning he wouldn't consider config2 = fill_with_defaults(configuration)
leading to buggy code (cuz changing one config affects other)

If you're not using the keys or values in bar why is it necessary to pass it in:

my_dict = {
    'a': 'b'
}

def foo():
    return dict(c='d')

my_dict.update(foo())

I would do:

my_dict = {
    'a': 'b'
}

def foo(bar):
    return dict(bar, **{'c':'d'})

my_dict = foo(my_dict)

It's essentially merge bar with whatever the other dict is, taking the latest key-value in case of conflict.

Not sure if it's canonical or most pythonish, however it's pretty clean way of doing what you're trying to do...

Related