Certamente Tallyson!

Os parâmetros *args e **kwargs são antigos companheiros, sendo eles respectivamente uma lista de valores com tamanho variável e um dicionário (chave - valor) de parâmetros.

*args = []

**kwargs = {}

Sendo assim o *args é utilizado para passar os parâmetros declarados na função.

Exemplo:

# Passando via *args os parâmetros declarados
def exemplo (nome, idade):
    print(f'Olá, {nome}, você tem {idade} anos.')

def args (*args):
    exemplo(*args)

args('João', 99)

Execução

Olá, João, você tem 99 anos.

Neste exemplo foi passada a quantidade de parâmetros exata, se for passado um número de parâmetros inferior ou superior a quantidade esperada, será gerada uma exceção.

O **kwargs é utilizado para passar parâmetros adicionais para a função e da mesma forma a função deve ter declarada o parâmetro **kwargs, para permitir os parâmetros adicionais.

# Passando os parâmetros obrigatórios via *args e mais parâmetros adicionais via **kwargs
def exemplo(nome, idade, **kwargs):
    # Imprime todos os parâmetros adicionais
    for arg, value in kwargs.items():
        print(f'{arg} = {value}')

    print(f'Olá, {nome}, você tem {idade} anos.')

def args(*args, **kwargs):
    exemplo(*args, **kwargs)

args('João', 99, pai = 'Carlos', mae = 'Joana', tio = 'Pedro')

Execução

pai = Carlos
mae = Joana
tio = Pedro
Olá, João, você tem 99 anos.

Overloaded

Os parâmetros adicionais passados via *kwargs são muito utilizados para configurar o comportamento do seu método, por exemplo configurar qual formatação utilizar, qual driver utilizar para calcular e etc.

Espero ter ajudado!