简体   繁体   中英

Template View - kwargs and **kwargs

I am reading about Template views through a tutorial and some of the code kind of confused me. The author used this code sample

from django.utils.timezone import now

class AboutUsView(TemplateView):
    template_name = 'about_us.html'

def get_context_data(self, **kwargs):
    context = super(AboutUsView, self).get_context_data(**kwargs)
    if now().weekday() < 5 and 8 < now().hour < 18:
        context['open'] = True
    else:
        context['open'] = False
    return context

The thing that confused me syntactically was this statement

 context = super(AboutUsView, self).get_context_data(**kwargs)

if we already are receiving **kwargs then why are we passing it to the super function with ** (double start). I think we should pass it as

 context = super(AboutUsView, self).get_context_data(kwargs)

this is the contextMixin which is receiving this call.

class ContextMixin(object):
    """
    A default context mixin that passes the keyword arguments received by
    get_context_data as the template context.
    """

    def get_context_data(self, **kwargs):
        if 'view' not in kwargs:
            kwargs['view'] = self
        return kwargs

From what I have read is that the use of **kwargs pretty much means that kwargs is currently a dictionary and needs to be converted to named-value. If that is correct then how can kwargs be a dictionary when its parameter is actually **kwargs. I hope my question makes sense. Please let me know if you would want me to rephrase this.

In a function declaration, **kwargs will take all unspecified keyword arguments and convert them into a dictionary.

>>> test_dict = {'a':1, 'b':2}
>>> def test(**kwargs):
...     print (kwargs)
...
>>> test(**test_dict)
{'b': 2, 'a': 1}

Note that the dictionary object has to be converted using ** when it is passed to the function ( test(**test_dict) ) and when it is received by the function. It is impossible to do the following:

>>> test(test_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: test() takes 0 positional arguments but 1 was given

So, in your example, the first **kwargs unpacks the keyword arguments into a dictionary, and then the second packs them back up to be sent to the parent.

A function with **kwargs in the signature can either received an unpacked dictionary or unspecified keyword arguments. Here's an example of the second case:

>>> def test(arg1, **kwargs):
...     print (kwargs)
...
>>> test('first', a=1, b=2)
{'b': 2, 'a': 1}

Here at your function definition, it is accepting multiple arguments, and parsing them into a dict. def get_context_data(self, **kwargs):

So now, kwargs is a dictionary object. So if you pass it to .get_context_data(kwargs) it would have to expect only a single incoming argument, and treat it as a dictionary.

So when you do **kwargs a second time, you are blowing up the dictionary back into keyword arguments that will expand into that functions call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM