views:

72

answers:

3

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.

+3  A: 
class MyClass(object):    
    def __init__(self, logger=None):
        self.logger = logger
    def test(self, **kwargs):
        logger = kwargs.get("logger", self.logger)
        # use logger, which is sourced as given in OP

Notes

  • The use of **kwargs is necessary as you're allowing None values for the logger named variable in MyClass.test. You could do away with this if you picked some other sentinel value (but None is most common).
  • It was unclear in the original question if you wanted a class or instance default. The one given above is an instance default, that is the default logger across all MyClass instances is None, set in the MyClass constructor.
Matt Joiner
Regarding note 1, couldn't you just use False as the sentinel value?
carl
You could use whatever you like, as long as you don't intend to pass it as a legitimate logger. Generally `None` is used, as I've explained. The OP could choose `42` as the sentinel if he so desired.
Matt Joiner
+1  A: 
class MyClass(object):
    def __init__(self, logger = None):
        self.logger = logger

    def test(self, **kwargs):
        logger = self.logger            
        if kwargs.has_key("logger"):
            logger = kwargs.get(logger)
        print "logger is %s" logger.name

Brief explanation: test starts off by assuming that it is going to use the instance logger. However if an explicit logger is passed in as command line argument it will be used instead. If logger = None is passed as a key word argument then no logger is used.

Manoj Govindan
+7  A: 
_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).

Alex Martelli