Search code examples
pythonnamed-parameters

How to use named parameters in Python methods that are defaulting to a class level value?


Usage scenario:

# case #1 - for classes
a = MyClass() # default logger is None
a = MyClass(logger="a") # set the default logger to be "a"
a.test(logger="b") # this means that logger will be "b" only inside this method
a.test(logger=None) # this means that logger will be None but only inside this method
a.test() # here logger should defaults to the value specified when object was initialized ("a")

How can I implement MyClass in order to be able to use it as above?

Let's assume that I have several methods inside MyClass that can accept the logger named parameter so I would appreciate a solution that does not require to add a lot of duplicate code at the beginning of each test...() method.

I read about the sentinel example, but this does not work for classes and I would not like to add a global variable to keep the sentinel object inside.


Solution

  • _sentinel = object()
    
    class MyClass(object):
      def __init__(self, logger=None):
        self.logger = logger
      def test(self, logger=_sentinel):
        if logger is _sentinel: logger = self.logger
    
    # in case you want to use this inside a function from your module use:
    _sentinel = object()
    logger = None
    def test(logger=_sentinel)
        if logger is _sentinel: logger = globals().get('logger')
    

    two core ideas: capturing the set of named values that may be (or may not be) locally overridden into a keywords-parameters dict; using a sentinel object as the default value to uniquely identify whether a certain named argument has been explicitly passed or not (None is often used for this purpose, but when, as here, you want None as a "first class value" for the parameter, a unique sentinel object will do just as well).