This is another default arguments question. The point is that when you write
def foo(value=VALUE):
the code inside the function is compiled and made into a function object. It is at this time -- not at call time! -- that the default arguments are stored. So by the time you have defined B
it is too late: the default value of foo
is already set and changing VALUE
won't have any effect.
If this seems a strange thing to do, suppose foo
was a global function:
default = 3
def foo(x=default): pass
Then any other code, anywhere, could screw up foo
by doing
global default
default = 4
This is arguably just as confusing.
To force the lookups to be done at runtime not compile time, you need to put them inside the function:
def foo(value=None):
self.value = self.VALUE if value is None else value
or (not quite the same but prettier)
self.value = value or self.VALUE
(This is different because it will treat any 'falsy' value as a sentinel -- that is, 0
, []
, {}
etc will all be overwritten by VALUE
.)
EDIT: @mgilson pointed out another way of doing this:
def foo(**kwargs):
self.value = kwargs.get("value", self.VALUE)
This is neater in that it doesn't require you to make a sentinel value (like None
or object()
, but it does change the argument specification of foo
quite fundamentally since now it will accept arbitrary keyword arguments. Your call.