bpo-36431: Use PEP 448 dict unpacking for merging two dicts. (GH-12553)

diff --git a/Lib/functools.py b/Lib/functools.py
index fe47600..426653f 100644
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -285,10 +285,7 @@
 
         if hasattr(func, "func"):
             args = func.args + args
-            tmpkw = func.keywords.copy()
-            tmpkw.update(keywords)
-            keywords = tmpkw
-            del tmpkw
+            keywords = {**func.keywords, **keywords}
             func = func.func
 
         self = super(partial, cls).__new__(cls)
@@ -302,9 +299,8 @@
         if not args:
             raise TypeError("descriptor '__call__' of partial needs an argument")
         self, *args = args
-        newkeywords = self.keywords.copy()
-        newkeywords.update(keywords)
-        return self.func(*self.args, *args, **newkeywords)
+        keywords = {**self.keywords, **keywords}
+        return self.func(*self.args, *args, **keywords)
 
     @recursive_repr()
     def __repr__(self):
@@ -371,8 +367,7 @@
             # it's also more efficient since only one function will be called
             self.func = func.func
             self.args = func.args + args
-            self.keywords = func.keywords.copy()
-            self.keywords.update(keywords)
+            self.keywords = {**func.keywords, **keywords}
         else:
             self.func = func
             self.args = args
@@ -391,11 +386,9 @@
 
     def _make_unbound_method(self):
         def _method(*args, **keywords):
-            call_keywords = self.keywords.copy()
-            call_keywords.update(keywords)
-            cls_or_self, *rest = args
-            call_args = (cls_or_self,) + self.args + tuple(rest)
-            return self.func(*call_args, **call_keywords)
+            cls_or_self, *args = args
+            keywords = {**self.keywords, **keywords}
+            return self.func(cls_or_self, *self.args, *args, **keywords)
         _method.__isabstractmethod__ = self.__isabstractmethod__
         _method._partialmethod = self
         return _method
diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py
index 9962477..f035bde 100644
--- a/Lib/idlelib/rpc.py
+++ b/Lib/idlelib/rpc.py
@@ -64,8 +64,7 @@
 
 
 class CodePickler(pickle.Pickler):
-    dispatch_table = {types.CodeType: pickle_code}
-    dispatch_table.update(copyreg.dispatch_table)
+    dispatch_table = {types.CodeType: pickle_code, **copyreg.dispatch_table}
 
 
 BUFSIZE = 8*1024
diff --git a/Lib/pdb.py b/Lib/pdb.py
index bf3219a..f5d33c2 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -491,8 +491,7 @@
         # Collect globals and locals.  It is usually not really sensible to also
         # complete builtins, and they clutter the namespace quite heavily, so we
         # leave them out.
-        ns = self.curframe.f_globals.copy()
-        ns.update(self.curframe_locals)
+        ns = {**self.curframe.f_globals, **self.curframe_locals}
         if '.' in text:
             # Walk an attribute chain up to the last part, similar to what
             # rlcompleter does.  This will bail if any of the parts are not
@@ -1377,8 +1376,7 @@
         Start an interactive interpreter whose global namespace
         contains all the (global and local) names found in the current scope.
         """
-        ns = self.curframe.f_globals.copy()
-        ns.update(self.curframe_locals)
+        ns = {**self.curframe.f_globals, **self.curframe_locals}
         code.interact("*interactive*", local=ns)
 
     def do_alias(self, arg):
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
index 9a3d399..df2ff06 100644
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -426,8 +426,7 @@
         self.unredirected_hdrs.pop(header_name, None)
 
     def header_items(self):
-        hdrs = self.unredirected_hdrs.copy()
-        hdrs.update(self.headers)
+        hdrs = {**self.unredirected_hdrs, **self.headers}
         return list(hdrs.items())
 
 class OpenerDirector:
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index c1cf483..b5ad8e1 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -169,10 +169,8 @@
         if not isinstance(attrib, dict):
             raise TypeError("attrib must be dict, not %s" % (
                 attrib.__class__.__name__,))
-        attrib = attrib.copy()
-        attrib.update(extra)
         self.tag = tag
-        self.attrib = attrib
+        self.attrib = {**attrib, **extra}
         self._children = []
 
     def __repr__(self):
@@ -451,8 +449,7 @@
     additional attributes given as keyword arguments.
 
     """
-    attrib = attrib.copy()
-    attrib.update(extra)
+    attrib = {**attrib, **extra}
     element = parent.makeelement(tag, attrib)
     parent.append(element)
     return element
diff --git a/Lib/xml/sax/saxutils.py b/Lib/xml/sax/saxutils.py
index a69c7f7..b4fc2da 100644
--- a/Lib/xml/sax/saxutils.py
+++ b/Lib/xml/sax/saxutils.py
@@ -56,8 +56,7 @@
     the optional entities parameter.  The keys and values must all be
     strings; each key will be replaced with its corresponding value.
     """
-    entities = entities.copy()
-    entities.update({'\n': '
', '\r': '
', '\t':'	'})
+    entities = {**entities, '\n': '
', '\r': '
', '\t':'	'}
     data = escape(data, entities)
     if '"' in data:
         if "'" in data: