Avoiding code repetition in default arguments in Python
Question: Consider a typical function with default arguments:

    
    
    def f(accuracy=1e-3, nstep=10):
        ...
    

This is compact and easy to understand. But what if we have another function
`g` that will call `f`, and we want to pass on some arguments of `g` to `f`? A
natural way of doing this is:

    
    
    def g(accuracy=1e-3, nstep=10):
        f(accuracy, nstep)
        ...
    

The problem with this way of doing things is that the default values of the
optional arguments get repeated. Usually when propagating default arguments
like this, one wants the same default in the upper function (`g`) as in the
lower function (`f`), and hence any time the default changes in `f` one needs
to go through all the functions that call it and update the defaults of any of
their arguments they would propagate to `f`.

Another way of doing this is to use a placeholder argument, and fill in its
value inside the function:

    
    
    def f(accuracy=None, nstep=None):
        if accuracy is None: accuracy = 1e-3
        if nstep is None: nstep=10
        ...
    def g(accuracy=None, nstep=None):
        f(accuracy, nstep)
        ...
    

Now the calling function doesn't need to know what `f`'s defaults are. But the
`f` interface is now a bit more cumbersome, and less clear. This is the
typical approach in languages without explicit default argument support, like
fortran or javascript. But if one does everything this way in python, one is
throwing away most of the language's default argument support.

Is there a better approach than these two? What is the standard, pythonic way
of doing this?


Answer: Define global constants:

    
    
    ACCURACY = 1e-3
    NSTEP = 10
    
    def f(accuracy=ACCURACY, nstep=NSTEP):
        ...
    
    def g(accuracy=ACCURACY, nstep=NSTEP):
        f(accuracy, nstep)
    

* * *

If `f` and `g` are defined in different modules, then you could make a
`constants.py` module too:

    
    
    ACCURACY = 1e-3
    NSTEP = 10
    

and then define `f` with:

    
    
    from constants import ACCURACY, NSTEP
    def f(accuracy=ACCURACY, nstep=NSTEP):
        ...
    

and similarly for `g`.

