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?
Use the Python **kwargs parameter to allow the function to accept a variable number of keyword arguments. Inside the function, the kwargs argument is a dictionary that contains all keyword arguments as its name-value pairs. Precede double stars ( ** ) to a dictionary argument to pass it to **kwargs parameter.
The double asterisk form of **kwargs is used to pass a keyworded, variable-length argument dictionary to a function. Again, the two asterisks ( ** ) are the important element here, as the word kwargs is conventionally used, though not enforced by the language.
__init__ is one of the magic methods that is defined inside a class and is called automatically when an instance of a class is created. It is sometimes known as dunder-init. It is used to initialize the instance variables. It takes default, keyworded and non-keyworded variable-length arguments.
**kwargs allows us to pass a variable number of keyword arguments to a Python function. In the function, we use the double-asterisk ( ** ) before the parameter name to denote this type of argument.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With