18

I would like to initialize a method's parameter with some default value if an explicit value was not passed into the method - something like this:

class Example
   def __init__(self, data = self.default_data()):
      self.data = data

   def default_data():
      # ....
      return something

I got the error:

NameError: name 'self' is not defined

How do I fix this?

alex
  • 6,818
  • 9
  • 52
  • 103
ceth
  • 44,198
  • 62
  • 180
  • 289
  • 1
    Related: http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument – Fred Foo Oct 25 '12 at 18:51

1 Answers1

24

The common idiom here is to set the default to some sentinel value (None is typical, although some have suggested Ellipsis for this purpose) which you can then check.

class Example(object): #inherit from object.  It's just a good idea.
   def __init__(self, data = None):
      self.data = self.default_data() if data is None else data

   def default_data(self):  #probably need `self` here, unless this is a @staticmethod ...
      # ....
      return something

You might also see an instance of object() used for the sentinel.

SENTINEL = object()
class Example(object):
   def __init__(self, data = SENTINEL):
      self.data = self.default_data() if data is SENTINEL else data

This latter version has the benefit that you can pass None to your function but has a few downsides (see comments by @larsmans below). If you don't forsee the need to pass None as a meaningful argument to your methods, I would advocate using that.

Community
  • 1
  • 1
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 2
    An `object()` as sentinel has the downside that it shows up really ugly in docstrings and the default behavior gets harder to obtain by explicit means, so passing `None` is the usual way of doing this (in the stdlib and most other Python libraries that I know). – Fred Foo Oct 25 '12 at 18:50
  • 1
    @larsmans -- I prefer `None` as well, but if `None` happens to be something you want to pass, then `object()` is the next best thing. If you really wanted, you could subclass object and just override `__repr__` to make `help` look nicer ... Also, if you import `Example`, you can also import `SENTINEL`. – mgilson Oct 25 '12 at 18:55
  • If Python 3.x is used, inheriting from `object` is automatic. – Noctis Skytower Oct 25 '12 at 18:59
  • 1
    @NoctisSkytower -- I'm well aware of that. But, I find that it's of practical merit to attempt to write code which plays nicely with both python2.x and python3.x -- Also there's a script 2to3, but not a 3to2 ... It's an easy thing to do and makes the code more portable. From that perspective, it just seems to make sense to inherit from `object` regardless. – mgilson Oct 25 '12 at 19:08
  • I asked a related question a while ago and one of the [answers](http://stackoverflow.com/a/6186450/566644) suggested using the built-in `Ellipsis` as sentinel. It doesn't have the disadvantages mentioned by @larsmans, I think. – Lauritz V. Thaulow Oct 25 '12 at 19:13
  • @lazyr -- Yes and no. You don't really see Ellipsis used except in the form `...` -- You couldn't call a function `foo(bar=...)` as that's a SyntaxError. You'd have to call it `module.foo(bar=Ellipsis)`. Personally, I'd rather have `module.foo(bar=module.SENTINEL)`. It seems more explicit to me. I suppose you could make `SENTINEL = Ellipsis` for the pretty printing ... Of course, these are all equivalent to `module.foo()`, but it matters in cases where you're packing `**kwargs` dynamically. – mgilson Oct 25 '12 at 19:19
  • 1
    In 3.x, '...' compiles to the `Ellipsis` singleton, so you actually can use `foo(bar=...)`. – Eryk Sun Oct 25 '12 at 19:29
  • @eryksun -- Yeah, I just learned that from the comments on the link I reposted from lazyr. That's pretty cool. – mgilson Oct 25 '12 at 19:30