pythonconstantsreadonlymutableinput-parameters

Pythonic way to distinguish read-only function input parameters from mutable ones


Python doesn't seem to have a valid const qualifier per How do I create a constant in Python? What would be the most "pythonic" way for differentiating read-only / mutable function parameters? Should I just point it out in the comments?

# my_graph is READ-ONLY
# my_set is added items with property X ...
def my_lovely_function(my_graph,my_set):

Solution

  • In C and several other languages, typically real outputs are communicated via inputs that are passed by pointers or by reference. The reason for this is that the return value mechanism in many of these paradigms has been hijacked for error handling purposes i.e. return value is a success/error code while useful outputs are populated in an input/pointer reference. This has led for the need to denote some inputs as being untouchable (consts) and others as being touchable to prevent confusion in using the function.

    Python typically doesn't want you to do things that way. It wants you to use Exceptions and exception handling for error handling and to use return statements for actual outputs. This is cleaner and more in line with the original idea of return values before they were highjacked by error handling.

    In some cases, it is still more convenient to use a mutable input to transfer data out. Everything in python is always by reference. This is fine except if the calling context doesn't want you, the function, to modify the variable it provided as an input.

    Python's solution is to 1) expect the function writer to properly document inputs, outputs, and side-effects on mutable inputs, and 2) provide the calling context the option of passing in immutable objects if they want to ensure those objects will not be changed.

    So if you have a list and you don't want some function you call to add or subtract things from it, pass in the information as a tuple instead. No function will be able to add or subtract anything to your tuple, however they might be able to change elements of the tuple if those are mutable. Instead of a set, pass a frozenset. There is no immutable dict type, but you can get around that by passing a copy or translating it to a frozenset of tuples. Strings, ints, floats, and complex numbers are all immutable. Note that mutable objects embedded in immutable containers can still be changed. If this is undesired, then make sure they are immutable. Alternatively, if you are paranoid, you can call copy.deepcopy() on an object to make a totally independent copy (recursively) to pass into the function. Any changes at any nested level of this deep copy will not affect the original object.

    When writing a function, it should be clear from the documentation (preferably docstring) or the code itself what the return values and side effects on mutable objects are. Using docstrings to capture this when writing a function is best practice.

    When calling a function, you should defensively make use of immutable types (or deep copying if need be) as needed for your specific circumstances.