6

Working with Sanic (async web framework in Python), I was trying to add custom data to a request:

request.user = 'A nice user'

But I was not able to, request is of type Request and does not allow this.

Looking at the source code for the Request class:

class Request(dict):
    """Properties of an HTTP request such as URL, headers, etc."""
    __slots__ = (
        'app', 'headers', 'version', 'method', '_cookies', 'transport',
        'body', 'parsed_json', 'parsed_args', 'parsed_form', 'parsed_files',
        '_ip', '_parsed_url', 'uri_template', 'stream', '_remote_addr',
        '_socket', '_port', '__weakref__'
    )

Looking up the internet, this dict inheritance has been added through a pull request to allow attaching data to a Request object.

So the recommended approach is:

request['user'] = 'A nice user'

This is all fine, I understand how it works.

However, I am confused by the usage of __slots__ on this class since it inherits from dict.

Another way to allow attaching data to this class' instances would have been to remove the __slots__ altogether (then we could have done request.user = ...).

The way I understand things, one use of __slots__ is to reduce the memory footprint of the object, preventing the creation of the __dict__ attribute.

But if we are inheriting from a dictionary does this still make sense?

Doing some command line tests with sys.getsizeof suggests it does not, but I'm not sure I can trust these.

How does this approach to allow adding data on the instances (using slots, inheriting from dict) compare to:

  1. Not using slots, not inheriting from dict.
    Would attribute access be slower (could not verify this in command line tests)?

  2. Adding '__dict__' to __slots__, not inheriting from dict.
    This answer on slots suggests it would give us the behavior we want.

Are there some other reasons why one would want to use __slots__ and inherit from dict here?

ldirer
  • 6,606
  • 3
  • 24
  • 30
  • 1
    `__slots__` avoids the overhead of an additional `dict` to store `Requests` attributes; the fact that it also inherits from `dict` doesn't change that. – chepner May 04 '18 at 15:09
  • I realize that, but does inheriting from dict not outweigh the gain of not creating the additional `dict`? Because we will still be creating a dictionary (the object itself!) if we inherit from `dict`. Probably my phrasing is non-optimal somewhere. – ldirer May 04 '18 at 15:13
  • 1
    No, because without `__slots__`, `Requests` both *is* a `dict` and *has* an additional `dict`. You still probably want to keep separate the data that a `Request` *stores* and the data that *describes* a `Request` object. – chepner May 04 '18 at 15:26
  • "You still probably want to keep separate the data that a Request stores and the data that describes a Request object." --> Thanks, this sounds like a relevant motivation for this approach. I would list it in 'other reasons' though since it's not related to performance. I'm still not sure about the approach vs the 2 alternatives that I mention in the question. – ldirer May 04 '18 at 15:37
  • could it be to freeze the attributes that can be assigned to Requests? for whatever reason the implementation feels that is useful. – JL Peyret May 05 '18 at 04:13

0 Answers0