简体   繁体   中英

In Python, is it bad form to set an argument's default value to be a function?

For example:

def wheels_factory_1():
    ...

def wheels_factory_2():
    ...

def make_car(wheels_factory_fn=wheels_factory_1):
    car = Car()
    car.add_wheels(wheels_factory_fn())
    return car

car1 = make_car()
car2 = make_car(wheels_factory_fn=wheels_factory_2)

Is it a common practice to set the default of wheels_factory_fn to be a function, like wheels_factory_1 ? I haven't seen this in a code base before, just wondering if there's some potential issue with doing this.

The reason why I want to structure code like this is to make it easy to do dependency injection.

Any default value which does not change over time should be good.

On the other hand, consider this example:

def foo(x=[]):
    x.append(1)
    print(x)

when called with an argument, behaves like a pure function :

>>> foo([1,2,3])
[1, 2, 3, 1]
>>> foo([1,2,3])
[1, 2, 3, 1]

but when called with the default value, it is something else...

>>> foo()
[1]
>>> foo()
[1, 1]

which may or may not be intended.

By using a function as the default value, you should be ok, as those are rarely modified in such a way.

Setting the default argument value to functions is common practice in machine learning libraries. Some image processing functions or transformations are set in the arguments which you have to explicitly mention.

It would be good if you can insert the default function value while instantiating the class.

something like this

class Car:
    def __init__(self, function = default_func):
        pass

This would be easy for injecting the dependencies. reference: https://medium.com/@shivama205/dependency-injection-python-cb2b5f336dce

For dependency injection, you can use dependency-injector .

Using a function as a default argument would work, but the general Best-Practice still holds:

When using a concrete value for the argument in the method signature:

  1. It creates dependency between the function logic and the default argument selection, which is exactly what you want to avoid.

This is solvable in our case by using the dependency injection, instead of the default argument.

  1. In case the function with the default argument is moved to another class, and one day you want to inherit from that class and change the default argument for the inheriting method, you shall set a default argument at the inherited class method too (problematic). The same applies when you have another function that calls the function with the default argument, and you want to change the default argument in it.

This is solvable in our case by avoiding the default argument or mitigated by default argument resolution like this:

def method(x=None):
    x = value if value else DEFAULT_VALUE

PS

Keep in mind that the default argument, is shared by the different invocations therefore usage of default mutable parameters (and in Python functions are first-class objects and mutable) should be with care.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM