voce pode tentar isso:

import time

ti = time.time()
while True:
    tf = time.time()
    dt = tf - ti 
    ti = tf
    
    if dt >= 500:
        if key[pygame.K_LEFT] or key[pygame.K_a]:
            new_posx -= 64
            self.context["direction"] = "WEST"
            self.frame_motion()
        if key[pygame.K_RIGHT] or key[pygame.K_d]:
            new_posx += 64
            self.context["direction"] = "EAST"
            self.frame_motion()
    
        if key[pygame.K_UP] or key[pygame.K_w]:
            new_posy -= 64
            self.context["direction"] = "NORTH"
            self.frame_motion()
            
        if key[pygame.K_DOWN] or key[pygame.K_s]:
            new_posy += 64
            self.context["direction"] = "SOUTH"
            self.frame_motion()
            if not self.check_map_colision(new_posx, new_posy):
                self.rect.x = new_posx
                self.rect.y = new_posy
                self.context["posx"] = self.rect.x
                self.context["posy"] = self.rect.y
                self.can_move = True
            else:
                self.can_move = False

Desta forma o movimento so ira ocorrer com um certo delay, mas nao afetar os updates. Claro que o 500 do if e um exemplo coloque o valor que achar melhor. Este valor é produzido em milissegundos só para ficar mais declarado.

Fonte: https://humberto.io/pt-br/blog/desbravando-o-pygame-5-movimento-e-colisao/