diff --git a/src/_pytest/python.py b/src/_pytest/python.py
index <HASH>..<HASH> 100644
--- a/src/_pytest/python.py
+++ b/src/_pytest/python.py
@@ -1658,25 +1658,20 @@ class Function(PyobjMixin, nodes.Item):
         # Note: when FunctionDefinition is introduced, we should change ``originalname``
         # to a readonly property that returns FunctionDefinition.name.
 
-        self.keywords.update(self.obj.__dict__)
         self.own_markers.extend(get_unpacked_marks(self.obj))
         if callspec:
             self.callspec = callspec
             self.own_markers.extend(callspec.marks)
-        if keywords:
-            self.keywords.update(keywords)
 
         # todo: this is a hell of a hack
         # https://github.com/pytest-dev/pytest/issues/4569
-
+        # Note: the order of the updates is important here; indicates what
+        # takes priority (ctor argument over function attributes over markers).
         # Take own_markers only; NodeKeywords handles parent traversal on its own.
-        self.keywords.update(
-            {
-                mark.name: mark
-                for mark in self.own_markers
-                if mark.name not in self.keywords
-            }
-        )
+        self.keywords.update({mark.name: mark for mark in self.own_markers})
+        self.keywords.update(self.obj.__dict__)
+        if keywords:
+            self.keywords.update(keywords)
 
         if fixtureinfo is None:
             fixtureinfo = self.session._fixturemanager.getfixtureinfo(
python: optimize node keywords initialization

If we do the `update`s in the right order, we can avoid the `mark.name
not in self.keywords` check, since `self.keywords` starts out clean and
`update` will override previously set keywords.