merge 3.4
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index e7f34cc..03dd545 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -77,9 +77,11 @@
         # exercise special code paths for no keyword args in
         # either the partial object or the caller
         p = self.partial(capture)
+        self.assertEqual(p.keywords, {})
         self.assertEqual(p(), ((), {}))
         self.assertEqual(p(a=1), ((), {'a':1}))
         p = self.partial(capture, a=1)
+        self.assertEqual(p.keywords, {'a':1})
         self.assertEqual(p(), ((), {'a':1}))
         self.assertEqual(p(b=2), ((), {'a':1, 'b':2}))
         # keyword args in the call override those in the partial object
diff --git a/Misc/NEWS b/Misc/NEWS
index 782bc69..13dd8c3 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -167,6 +167,8 @@
   lines from the code object, fixing an issue when a lambda function is used as
   decorator argument. Patch by Thomas Ballinger and Allison Kaptur.
 
+- The keywords attribute of functools.partial is now always a dictionary.
+
 - Issue #23811: Add missing newline to the PyCompileError error message.
   Patch by Alex Shkop.
 
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index 3413b12..3c82e51 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -102,8 +102,17 @@
         }
     }
     else {
-        pto->kw = pkw;
-        Py_INCREF(pkw);
+        if (pkw == Py_None) {
+            pto->kw = PyDict_New();
+            if (pto->kw == NULL) {
+                Py_DECREF(pto);
+                return NULL;
+            }
+        }
+        else {
+            pto->kw = pkw;
+            Py_INCREF(pkw);
+        }
     }
 
     pto->weakreflist = NULL;