codecov-io: ## [Current coverage](https://codecov.io/gh/falconry/falcon/pull/868?src=pr) is 100% (diff: 100%)
> Merging [#868](https://codecov.io/gh/falconry/falcon/pull/868?src=pr) into [master](https://codecov.io/gh/falconry/falcon/branch/master?src=pr) will not change coverage

```diff
@@           master   #868   diff @@
====================================
  Files          30     30          
  Lines        1864   1864          
  Methods         0      0          
  Messages        0      0          
  Branches      305    305          
====================================
  Hits         1864   1864          
  Misses          0      0          
  Partials        0      0          
```

> Powered by [Codecov](https://codecov.io?src=pr). Last update [fd5a0ba...dbf09ee](https://codecov.io/gh/falconry/falcon/compare/fd5a0ba5874c68e2a61470180455c8e05c3d3d66...dbf09ee6361a2abaa9ceaae5e4fedc77fefad291?src=pr)
diff --git a/falcon/request.py b/falcon/request.py
index 30a2bd3..dd49159 100644
--- a/falcon/request.py
+++ b/falcon/request.py
@@ -243,6 +243,7 @@ class Request(object):
         'options',
         '_cookies',
         '_cached_access_route',
+        '__dict__',
     )
 
     # Child classes may override this
diff --git a/falcon/response.py b/falcon/response.py
index 44d3d5d..fd25479 100644
--- a/falcon/response.py
+++ b/falcon/response.py
@@ -116,6 +116,7 @@ class Response(object):
         'stream',
         'stream_len',
         'context',
+        '__dict__',
     )
 
     # Child classes may override this

Make it easier to add custom attributes to slotted classes 
Users of the framework sometimes want to assign additional variables to the `Request`, `Response`, or other "slotted" classes. This can be allowed without hurting efficiency by adding a `'__dict__'` string to the `__slots__` declarations.

From the Python [data model docs](https://docs.python.org/2/reference/datamodel.html#slots): 

> Without a __dict__ variable, instances cannot be assigned new variables not listed in the __slots__ definition. Attempts to assign to an unlisted variable name raises AttributeError. If dynamic assignment of new variables is desired, then add '__dict__' to the sequence of strings in the __slots__ declaration.

I did a quick test and adding '__dict__' does not decrease performance for accessing the other slotted variables in 2.7 and 3.5. 

Question: Does this enable an anti-pattern? Would we rather that apps use `req.context`? Would it be better to have a context type that supports attribute-based access? (e.g., `req.context.foo` == `req.context['foo']`)?
diff --git a/tests/test_slots.py b/tests/test_slots.py
new file mode 100644
index 0000000..665ea32
--- /dev/null
+++ b/tests/test_slots.py
@@ -0,0 +1,22 @@
+from falcon import Request, Response
+import falcon.testing as testing
+
+
+class TestSlots(testing.TestBase):
+
+    def test_slots_request(self):
+        env = testing.create_environ()
+        req = Request(env)
+
+        try:
+            req.doesnt = 'exist'
+        except AttributeError:
+            self.fail('Unable to add additional variables dynamically')
+
+    def test_slots_response(self):
+        resp = Response()
+
+        try:
+            resp.doesnt = 'exist'
+        except AttributeError:
+            self.fail('Unable to add additional variables dynamically')

pip install -e .
parse_log_pytest
requirements.txt
nose ddt testtools requests pyyaml pytest
apt-get update apt-get install -y gcc
3.5
tools/test-requires
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
charset-normalizer==2.0.12
coverage==6.2
ddt==1.7.2
-e git+https://github.com/falconry/falcon.git@fd5a0ba5874c68e2a61470180455c8e05c3d3d66#egg=falcon
fixtures==4.0.1
idna==3.10
importlib-metadata==4.8.3
iniconfig==1.1.1
nose==1.3.7
packaging==21.3
pbr==6.1.1
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
python-mimeparse==1.6.0
PyYAML==6.0.1
requests==2.27.1
six==1.17.0
testtools==2.6.0
tomli==1.2.3
typing_extensions==4.1.1
urllib3==1.26.20
zipp==3.6.0

name: falcon
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - charset-normalizer==2.0.12
      - coverage==6.2
      - ddt==1.7.2
      - fixtures==4.0.1
      - idna==3.10
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - nose==1.3.7
      - packaging==21.3
      - pbr==6.1.1
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - python-mimeparse==1.6.0
      - pyyaml==6.0.1
      - requests==2.27.1
      - six==1.17.0
      - testtools==2.6.0
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - zipp==3.6.0
prefix: /opt/conda/envs/falcon

tests/test_slots.py::TestSlots::test_slots_request tests/test_slots.py::TestSlots::test_slots_response
falcon/request.py falcon/response.py
falcon/request.py falcon/response.py