Trying to figure out how this code is working.
I understand that **kwargs
returns a dictionary and the get()
function searches the dict for a given key and returns a default value if not found.
However in the code I don't understand is if the get()
method is searching for example: "clock" or self.clock or both.
def update(self, *args, **kwargs):
self.screen = kwargs.get("screen",self.screen)
self.clock = kwargs.get("clock",self.clock)
self.active = kwargs.get("active",self.active)
Here is an example call to this method:
debug.update(active = numActive)
From my understanding, the variable numActive
is passed through the update method as active and then as **kwargs
which is then searched for via the get()
method. Couldn't I just remove the use of kwargs
seeing as I know how many parameters are needed?
Any help with understanding is appreciated.
The second parameter in the get method is the default value.
According to Python2.7's documentation:
get(key[, default])
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
Source: https://docs.python.org/2/library/stdtypes.html#dict.get
Explanation When you try to 'get' something from a dictionary, if the key is not found, or the value is None, it will return None.
BUT, if you provide the second parameter (which is the default), if and only if the key is not found, default value will be returned.
Example without defaults
For the following code:
some_dict = {
"key_1": 1,
"key_2": None,
}
print some_dict.get("key_1")
print some_dict.get("key_2")
print some_dict.get("key_3")
You will get the output:
1
None
None
Example with defaults
For the following code
some_dict = {
"key_1": 1,
"key_2": None,
}
print some_dict.get("key_1", 1)
print some_dict.get("key_2", 2)
print some_dict.get("key_3", 3)
You will get the output:
1
None
3
Looking at your code
I will explain your code in the comments:
def update(self, *args, **kwargs):
# If the kwargs contain the key 'screen', the following get method will
# return its value, or else it would remain whatever value was in
# self.screen's variable before
self.screen = kwargs.get("screen",self.screen)
# If the kwargs contain the key 'clock', the following get method will
# return its value, or else it would remain whatever value was in
# self.clock's variable before
self.clock = kwargs.get("clock",self.clock)
# If the kwargs contain the key 'active', the following get method will
# return its value, or else it would remain whatever value was in
# self.active's variable before
self.active = kwargs.get("active",self.active)
Hope this helps. Cheers.
This expression:
kwargs.get("screen",self.screen)
is equivalent to this expression:
kwargs["screen"] if "screen" in kwargs else self.screen
This statement:
self.screen = kwargs.get("screen",self.screen)
is equivalent to these statements:
if "screen" in kwargs:
self.screen = kwargs["screen"]
else:
self.screen = self.screen
Note that it is not equivalent to these statements:
if "screen" in kwargs:
self.screen = kwargs["screen"]
Because the statement
self.screen = self.screen
raises an AttributeError
if self.screen
is not yet defined. See that error in action by running the following program:
d = {}
x = object()
x.attr = d.get("attr", x.attr)
You can do away with kwargs
by implementing update
instead as:
def update(self, screen=None, clock=None, active=None):
if screen is not None: self.screen = screen
if clock is not None: self.clock = clock
if active is not None: self.active = active
And then you can call debug.update
and specify whichever of the keyword arguments you want. Defining it this way has the advantage that it raises a TypeError
if you try to call it with a keyword argument other than screen
, clock
, or active
.
One caveat is that if you really mean to say debug.update(screen = None)
, then calling it that way actually does nothing; it does not set debug.screen
to None
. One way to get around that is to write this at the top of your file:
_UNSPECIFIED = object()
And then implement update
as:
def update(self, screen=_UNSPECIFIED, clock=_UNSPECIFIED, active=_UNSPECIFIED):
if screen is not _UNSPECIFIED: self.screen = screen
if clock is not _UNSPECIFIED: self.clock = clock
if active is not _UNSPECIFIED: self.active = active
kwargs.get()
retrieves a keyword argument passed to a function.
The first argument is the keyword and the second is the default value if there was no argument provided for the keyword.
from uuid import uuid4
def my_function(**kwargs):
id = kwargs.get("id", uuid4().hex[:6])
name = kwargs.get("name", None)
print(f"{id} - {name}")
my_function(name="Alice")
a1b2c3 - Alice
my_function(name="Bob", id="d4e5f6")
d4e5f6 - Bob
my_function()
g7h8i9 - None
self.screen = kwargs.get("screen",self.screen)
This gets the "screen" value from kwargs
. If its not there, it just uses whatever happens to be in screen at the moment and stuffs it back into screen. Its the same as
if "screen" in kwargs:
self.screen = kwargs["screen"]
In other words, update
only changes values that are passed as keyword arguments. This seems like a complicated way to do a simple thing. There must be a use case for it, but, generally, yuck.
Couldn't I just remove the use of kwargs seeing as I know how many parameters are needed?
In the example, no. It will set zero, onem two or three attributes depending on whether they are in kwarg
. You could even put other values like update(foo="bar")
and it would just ignore them.
So, here are two ways to set the attribute:
debug.update(active = numActive)
debug.active = numActive
I'm leaning towards the second way. Leaning way over!
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