We can implement this with caching in order to do this recursively.
class Solution:
@lru_cache
def isMatch(self, s: str, p: str) -> bool:
if not p:
return not s
if not s:
return len(p) > 1 and p[1] == '*' and self.isMatch(s, p[2:])
matched = (p[0] == '.' or p[0] == s[0])
if len(p) > 1 and p[1] == '*':
return (matched and self.isMatch(s[1:], p)) or self.isMatch(s, p[2:])
return matched and self.isMatch(s[1:], p[1:])