Search code examples
pythoninstance-variablesdefault-arguments

How can I use an attribute of the instance as a default argument for a method?


I want to pass a default argument to an instance method using the value of an attribute of the instance:

class C:
    def __init__(self, format):
        self.format = format

    def process(self, formatting=self.format):
        print(formatting)

When trying that, I get the following error message:

NameError: name 'self' is not defined

I want the method to behave like this:

C("abc").process()       # prints "abc"
C("abc").process("xyz")  # prints "xyz"

What is the problem here, why does this not work? And how could I make this work?


Solution

  • You can't really define this as the default value, since the default value is evaluated when the method is defined which is before any instances exist. The usual pattern is to do something like this instead:

    class C:
        def __init__(self, format):
            self.format = format
    
        def process(self, formatting=None):
            if formatting is None:
                formatting = self.format
            print(formatting)
    

    self.format will only be used if formatting is None.


    To demonstrate the point of how default values work, see this example:

    def mk_default():
        print("mk_default has been called!")
    
    def myfun(foo=mk_default()):
        print("myfun has been called.")
    
    print("about to test functions")
    myfun("testing")
    myfun("testing again")
    

    And the output here:

    mk_default has been called!
    about to test functions
    myfun has been called.
    myfun has been called.
    

    Notice how mk_default was called only once, and that happened before the function was ever called!