Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class methods in python: default kwargs from attributes of self

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?

like image 549
corvus Avatar asked Jun 18 '18 05:06

corvus


People also ask

How do you pass Kwargs in a class Python?

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.

What is the correct way to use the Kwargs statement?

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.

What are the default arguments for __ Init__ method?

__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.

How do you give Kwargs in Python?

**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.


1 Answers

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.

like image 87
abarnert Avatar answered Oct 06 '22 15:10

abarnert