6

Is it possible to define a class method which takes an attribute of self as a default keyword argument? i.e. I'd like to do something equivalent to the following:

class Foo:
    def __init__(self, bar):
        self.bar = bar

    def do_a_thing(self, my_arg=self.bar):
        do_something_else(my_arg)

Of course this throws an error:

x = Foo(y)
x.do_a_thing()

NameError: name 'self' is not defined

Hopefully it is clear what kind of behavior I am hoping to get. Calling x.do_a_thing() should be equivalent to x.do_a_thing(my_arg=x.bar).

Is there a way to do this?

2 Answers 2

8

Whenever you want a default value that can't easily be specified statically, the idiom is to use a sentinel value.

If None is not a valid value that anyone might ever pass, use that:

def do_a_thing(self, my_arg=None):
    if my_arg is None:
        my_arg = self.bar
    do_something_else(my_arg)

Or, if there's no falsey value that would ever be valid:

def do_a_thing(self, my_arg=None):
    if not my_arg:
        my_arg = self.bar
    do_something_else(my_arg)

Or, if even None could be a value, you need to create a private sentinel that nobody will ever pass:

_sentinel = object()
def do_a_thing(self, my_arg=_sentinel):
    if my_arg is _sentinel:
        my_arg = self.bar
    do_something_else(my_arg)

By the way, calling this a "default keyword argument" implies a serious misunderstanding. The fact that the syntax for default values in function definitions looks similar to the syntax for keyword arguments in function calls is a coincidence. In particular, this is not a keyword parameter, and it can be called without using keyword arguments. For example:

my_thing.do_a_thing(20)

If you actually want a keyword-only parameter, it has to come after a * (or after *args, if you have one of those). And, because these are completely unrelated features, you can have keyword-only parameters without default values:

def do_a_thing(self, *, my_arg):
    do_something_else(my_arg)

And "kwargs" usually isn't used as shorthand for "keyword argument" or "keyword parameter", but rather for the **kwargs parameter that gathers all unknown keyword arguments.

Sign up to request clarification or add additional context in comments.

Comments

2

When the parameters to do_a_thing are evaluated, there is no reference to self. That is why it is not working.

You need to use the common default argument pattern, like this

class Foo:
    def __init__(self, bar):
        self.bar = bar

    def do_a_thing(self, my_arg=None):
        if my_arg is None:
            my_arg = self.bar
        do_something_else(my_arg)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.