1

I'm currently working with a pre-existing class (not written by me) that has functions which call other functions, passing through the parameters to the helper functions. Sometimes there are layers to these functions, so that func1 calls func2 calls func3 calls func4, where a parameter of func4 is passed through all the way from func1. In this case, it would not make sense to make any of these parameters instance/class attributes.

A 1-layer example:

def my_func(A, B, C, D):
    # Calculate E with my_func args
    E = some_calculations(A, B)

    # Call helper, passing through some parameters
    return helper(C=C, D=D, E=E)

def helper(c, d, e):
    return some_other_calculations(C, D, E)

I'm trying to write some dosctrings for these functions, and I am having trouble formulating a way to effecitvely document the arguments that are passed through to the helper function(s).

In particular, I see a few options:

Method 1

Point to helper's dosctring:

def my_func(A, B, C, D):
    """
    Do some stuff
    :param A: Parameter A description
    :param B: Parameter B description
    :param C: See `helper` 
    :param D: See `helper`
    """
    ...
    return helper(...)

def helper(C, D, E)
    """
    Do some other stuff
    :param C: Parameter C description
    :param D: Parameter D description
    :param E: Parameter E description
    """
    ...
    return some_other_calculations(...)

PRO: Only ever have to update/maintain one description of a given parameter

CON: If we add another function outer_func that calls my_func and passes C and D to it, which in turn passes C and D to helper, we will have to point to either my_func or helper.

In the former case this would lead to another forwarding, daisy-chaining the reader through multiple dosctrings just to get a description. In the latter case, it would be unclear where in outer_func that helper is called.

Method 2

Simply copy the description for each function that uses it

def my_func(A, B, C, D):
    """
    Do some stuff
    :param A: Parameter A description
    :param B: Parameter B description
    :param C: Parameter C description
    :param D: Parameter D description
    """
    ...
    return helper(...)

def helper(C, D, E)
    """
    Do some other stuff
    :param C: Parameter C description
    :param D: Parameter D description
    :param E: Parameter E description
    """
    ...
    return some_other_calculations(...)

PRO: Do not have to look through other functions to understand the argument

CON: Obviously, multiple descriptions will have to be maintained. Also, it may difficult to describe the parameters without reference to the functions which use them, in which case you are probably forwarding them to the other functions anyway. This effectively leads to the cons of method 1 without the pro.

Method 3

Brief description + forwarding

def my_func(A, B, C, D):
    """
    Do some stuff
    :param A: Parameter A description
    :param B: Parameter B description
    :param C: Brief parameter C description. See `helper` for more info.
    :param D: Brief parameter D description. See `helper` for more info.
    """
    ...
    return helper(...)

def helper(C, D, E)
    """
    Do some other stuff
    :param C: Parameter C description
    :param D: Parameter D description
    :param E: Parameter E description
    """
    ...
    return some_other_calculations(...)

The pros/cons here are kind of a blend of the above two methods

Method 4

Something else?

Any advice is greatly appreciated!

1
  • @PhilipKendall they are in the class's public API but that was my first thought as well - I do not believe they need to be. I guess I will see if we can make them private because the doccing is getting quite cumbersome. Thanks for your advice!
    – WhoDatBoy
    Jul 11 at 17:19

2 Answers 2

2

You do not need to document the fact that a parameter is passed through to another function. Doing this exposes implementation details that are not relevant to the use case your function fulfills. Instead, use the docstring comments to describe that parameter within the context of the method that calls the helper.

The docstring comments for the helper method should probably be very general. Presumably the helper is used in a larger number of use cases, therefore the phrasing used to describe the helper method parameters will be very generic. The docstring comments for the method which calls the helper should be use case-specific.

The names of functions chosen for the question are too generic to give you specific advice. Instead, let's use a contrived example that at least gives us a concrete use case.

Say you have a method which formats the price for an entire shopping cart. That method calls a helper to format a number as currency (the helper method).

def format_shopping_cart_price(shopping_cart, currency_format)
  return format_currency(shopping_cart.price, currency_format)

def format_currency(amount, currency_format)
  return ...

In each case, phrase docstring comments so they make sense within the context the method gets used. The format_currency method is general purpose, so the words used to describe the parameters should also be general purpose. Frankly, even the parameter names should be general purpose:

def format_currency(amount, currency_format)
  # :param amount: The amount to format as currency
  # :param currency_format: A currency format string
  return ...

The words "amount" and "currency format" can be applied to any use case where you have a number that should be formatted as currency.

The format_shopping_cart_price method is use case-specific: it formats the total price of a shopping cart as currency. Even though the currency_format parameter is simply passed to the helper method, the docstring comment can be tailored to the use case of formatting the shopping cart price:

def format_shopping_cart_price(shopping_cart, currency_format)
  # :param shopping_cart: The shopping cart whose total price should be formatted as currency
  # :param currency_format: The currency format string used to format the shopping cart price
  return format_currency(shopping_cart.price, currency_format)

In the example above, the term "amount" is basically replaced by "shopping cart price". Copying and pasting docstring comments, while easy, isn't necessarily desirable. You miss opportunities to use docstring comments to communicate use case-specific information that aids other programmers in calling your methods.

I'll end this with one more possible solution to this conundrum. Does a "helper" method need docstring comments? Does your other function need docstring comments? By carefully choosing class, method, and parameter names you can often skip writing comments. The names of things are enough of a description that docstring comments are extra work for no extra value.

1
  • Thanks for this answer - that makes a lot of sense. The particular use case is instructional - explaining a neural network - so even methods that could be private I want to document in the case that someone wants to dive into the details of the implementation. I will think about the best way to communicate this information, taking all of your advice into account. Thanks very much
    – WhoDatBoy
    Jul 11 at 21:51
0

Does helper need to be part of your class's public API? If not, it's an implementation detail and doesn't need to be documented - or at least, doesn't need a formal docstring.

3
  • It does not need to be public but the class is a neural network so I want to document it's inner workings so that readers can understand it's implementation. The code will not be put into production and will only be used for educational purposes.
    – WhoDatBoy
    Jul 11 at 21:53
  • 1
    @WhoDatBoy: what you are proposing is not a good use case for docstring comments. Consider using diagrams, or even perhaps a dedicated markdown-driven section of your code base to communicate that level of detail. It almost sounds like you want architectural or instructional documentation rather than API documentation. Jul 11 at 22:34
  • @GregBurghardt thanks for that input - I will look into other options
    – WhoDatBoy
    Jul 11 at 22:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.