61

Possible Duplicate:
default value of parameter as result of instance method

While it is possible to set default values to function parameters in python:

def my_function(param_one='default')
    ...

It seems not to be possible to access the current instance (self):

class MyClass(..):

    def my_function(self, param_one=self.one_of_the_vars):
        ...

My question(s):

  • Is this true that I cannot access the current instance to set the default parameter in functions?
  • If it is not possble: what are the reasons and is it imaginable that this will be possible in future versions of python?
Georgy
  • 12,464
  • 7
  • 65
  • 73
paweloque
  • 18,466
  • 26
  • 80
  • 136
  • This is a bit different, Ashwini. That post was asking about instance methods, this is about instance attributes. The reason both are problematic is the same, yes, but the question is definitely different. – Alex V Nov 02 '12 at 13:24
  • @Maxwell but it's somewhat same, as he's trying to use `self.someattribute` in default argument value. – Ashwini Chaudhary Nov 02 '12 at 13:26
  • 1
    @Ashwini Sure, but that is not a reason to vote to close as a duplicate, since the requirement is that it's an *exact duplicate* that covers *exactly the same content* and that the answers to this question may be merged in along with those of the other question. Implicit in the "may be merged" formulation is that those merged questions should not stick out like sore thumbs because they do not answer the question. – Lauritz V. Thaulow Nov 02 '12 at 13:30
  • @lazyr It didn't vote, some one else did it. I just added the comment. – Ashwini Chaudhary Nov 02 '12 at 13:32
  • 1
    The important point is that the default parameters are set up at __define time__, but that `self` doesn't exist until __runtime__. – Katriel Nov 02 '12 at 13:48

4 Answers4

62

It's written as:

def my_function(self, param_one=None): # Or custom sentinel if None is vaild
    if param_one is None:
        param_one = self.one_of_the_vars

And I think it's safe to say that will never happen in Python due to the nature that self doesn't really exist until the function starts... (you can't reference it, in its own definition - like everything else)

For example: you can't do d = {'x': 3, 'y': d['x'] * 5}

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
  • 2
    This is a good answer. I think it would be even more instructive to write a function: `def my_func(a, foo=a.bar): ...` and show how that function doesn't work because `a` is a parameter to the function, but the default value for `foo` is associated when the function is defined. It's kind of nice to see that there's nothing actually special about `self`. It's just a parameter in the function call like everything else -- (It just happens to be a parameter that is passed implicitly when you do `instance.method()`). – mgilson Nov 02 '12 at 13:30
  • 1
    Just for the sake of completeness: if your `one_of_the_vars` happens to be a constant attribute defined in SAME class, you can then simply reference it in your method by `def my_function(self, param_one=ONE_OF_THE_CONSTANTS)`. It will work. – RayLuo Aug 31 '16 at 18:48
24

There is much more to it than you think. Consider the defaults to be static (=constant reference pointing to one object) and stored somewhere in the definition; evaluated at method definition time; as part of the class, not the instance. As they are constant, they cannot depend on self.

Here is an example. It is counterintuitive, but actually makes perfect sense:

def add(item, s=[]):
    s.append(item)
    print len(s)

add(1)     # 1
add(1)     # 2
add(1, []) # 1
add(1, []) # 1
add(1)     # 3

This will print 1 2 1 1 3.

Because it works the same way as

default_s=[]
def add(item, s=default_s):
    s.append(item)

Obviously, if you modify default_s, it retains these modifications.

There are various workarounds, including

def add(item, s=None):
    if not s: s = []
    s.append(item)

or you could do this:

def add(self, item, s=None):
    if not s: s = self.makeDefaultS()
    s.append(item)

Then the method makeDefaultS will have access to self.

Another variation:

import types
def add(item, s=lambda self:[]):
    if isinstance(s, types.FunctionType): s = s("example")
    s.append(item)

here the default value of s is a factory function.

You can combine all these techniques:

class Foo:
    import types
    def add(self, item, s=Foo.defaultFactory):
        if isinstance(s, types.FunctionType): s = s(self)
        s.append(item)

    def defaultFactory(self):
        """ Can be overridden in a subclass, too!"""
        return []
Has QUIT--Anony-Mousse
  • 76,138
  • 12
  • 138
  • 194
  • 1
    I don't know that I would use the term *constants* here as you can mutate the object. But pointing out that the defaults are associated with keywords when the function is *defined* is helpful. – mgilson Nov 02 '12 at 13:25
  • Thanks, yeah, I mean *static*. – Has QUIT--Anony-Mousse Nov 02 '12 at 13:27
  • 1
    @mgilson it is a constant object reference; if the object is mutable it can be mutated, but the reference cannot be changed. While the term _constant_ may be confusing it is fitting if you think of it as a reference. – l4mpi Nov 02 '12 at 13:32
  • I've also added some more solutions to get the desired behavior: factory functions, or delegating default value initialization to a separate method. – Has QUIT--Anony-Mousse Nov 02 '12 at 13:36
  • 1
    @l4mpi -- You're absolutely correct about it being a constant *reference*, but I think that the term is still confusing to someone who might be asking a question like this. – mgilson Nov 02 '12 at 13:37
3

Default value for parameters are evaluated at "compilation", once. So obviously you can't access self. The classic example is list as default parameter. If you add elements into it, the default value for the parameter changes!

The workaround is to use another default parameter, typically None, and then check and update the variable.

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
2

There are multiple false assumptions you're making here - First, function belong to a class and not to an instance, meaning the actual function involved is the same for any two instances of a class. Second, default parameters are evaluated at compile time and are constant (as in, a constant object reference - if the parameter is a mutable object you can change it). Thus you cannot access self in a default parameter and will never be able to.

l4mpi
  • 5,103
  • 3
  • 34
  • 54