1

I want to write a method like this:

def method(self, long_api_parameter_name=None):
    if long_api_parameter_name is None:
        long_api_parameter_name = self.DEFAULT_X

    return self.another_method(long_api_parameter_name)

However I have been advised not to reassign to a method parameter. Is there any [semi]official recommendation or at least a consensus within the community?

abukaj
  • 2,582
  • 1
  • 22
  • 45
  • 1
    I personally do this kind of thing all the time. Maybe I would advise against using a parameter exactly like a local variable, assigning it multiple times for example (it may be confusing if later at some point you want "what was passed to the function"), but this kind of "default value" case I think completely reasonable. You could use a different variable if you wanted but I'm not sure how that should help. – jdehesa Apr 26 '19 at 16:08
  • 1
    This is practically the recommended way to deal with a parameter whose default value should be mutable. Who told you *not* to do this? – chepner Apr 26 '19 at 16:24
  • @chepner I think it has been R. C. Martins in his _Clean Code_ lectures but would have to watch them again. It is also mentioned as _generally bad idea_ in the last paragraph of https://spin.atomicobject.com/2011/04/10/javascript-don-t-reassign-your-function-arguments/ (just before _Additional information_; previous paragraphs are solely about JS). – abukaj Apr 26 '19 at 16:33
  • Not exactly authoritative advice. Other languages may have to worry about aliasing, where reassigning to a parameter may change a variable in the calling scope. Not so in Python; a parameter is just a local variable, one that happens to be initialized for you. [There](https://github.com/python/cpython/blob/master/Lib/functools.py#L711) [are](https://github.com/python/cpython/blob/master/Lib/collections/__init__.py#L380) [examples](https://github.com/python/cpython/blob/master/Lib/subprocess.py#L726) in the standard library of just this kind of rebinding. – chepner Apr 26 '19 at 16:39

2 Answers2

0

I would probably write it as

long_api_parameter_name = long_api_parameter_name or self.DEFAULT_X

for brevity, but yes, it's a pretty common pattern in Python.

Update:

If the passed value might evaluate as false, you have to do something slightly more complex:

NOT_PASSED = object()

def method(self, long_api_parameter_name=NOT_PASSED):
    long_api_parameter_name = long_api_parameter_name if long_api_parameter_name is not NOT_PASSED else self.DEFAULT_X

This will allow false values - even None to be explicitly passed, but fall back to the default if nothing is specified.

brunns
  • 2,689
  • 1
  • 13
  • 24
  • Unfortunately the ternary operator expression is the source of my original problem: https://stackoverflow.com/questions/55870257/what-is-the-recommended-layout-for-splitting-ternary-operator-into-multiple-line – abukaj Apr 26 '19 at 16:24
  • 2
    Use `is not` instead of `!=` for comparing to your sentinel; it is by definition a unique object. – chepner Apr 26 '19 at 16:27
0

There is no official statement on reassigning method arguments in the Python docs or PEP style guidelines, as far as I can tell.

The answer by brunns is a good way to achieve what you're looking for.

**Be aware that the value will only be reassigned within your call to method... see this question

Some people consider this bad practice because there are other languages whose standards state that method/function parameters should not be reassigned. (e.g. Javascript)