Giving credit for @Ruzihm's answer since parts of my answer derive from his.
Quick overview
A quick rundown of the differences:
re.match is anchored at the start ^pattern
- Ensures the string begins with the pattern
re.fullmatch is anchored at the start and end of the pattern ^pattern$
- Ensures the full string matches the pattern (can be especially useful with alternations as described here)
re.search is not anchored pattern
- Ensures the string contains the pattern
A more in-depth comparison of re.match vs re.search can be found here
With examples:
aa # string
a|aa # regex
re.match: a
re.search: a
re.fullmatch: aa
ab # string
^a # regex
re.match: a
re.search: a
re.fullmatch: # None (no match)
So what about \A and \Z anchors?
The documentation states the following:
Python offers two different primitive operations based on regular
expressions: re.match() checks for a match only at the beginning of
the string, while re.search() checks for a match anywhere in the
string (this is what Perl does by default).
And in the Pattern.fullmatch section it says:
If the whole string matches this regular expression, return a corresponding match object.
And, as initially found and quoted by Ruzihm in his answer:
Note however that in MULTILINE mode match() only matches at the
beginning of the string, whereas using search() with a regular
expression beginning with ^ will match at the beginning of each
line.
>>> re.match('X', 'A\nB\nX', re.MULTILINE) # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE) # Match
<re.Match object; span=(4, 5), match='X'>
\A^A
B
X$\Z
# re.match('X', s) no match
# re.search('^X', s) no match
# ------------------------------------------
# and the string above when re.MULTILINE is enabled effectively becomes
\A^A$
^B$
^C$\Z
# re.match('X', s, re.MULTILINE) no match
# re.search('^X', s, re.MULTILINE) match X
With regards to \A and \Z, neither performs differently for re.MULTILINE since \A and \Z are effectively the only ^ and $ in the whole string.
So using \A and \Z with any of the three methods yields the same results.
Answer (line anchors vs string anchors)
What this tells me is that re.match and re.fullmatch don't match line anchors ^ and $ respectively, but that they instead match string anchors \A and \Z respectively.