Executando verificação de segurança...
Em resposta a [Não disponível]
15

Antes, umas correções: na primeira função o return value está dentro do else. Ou seja, em vez disso:

    else:
        value == None
        return value # return está dentro do else

Deveria ser isso:

    else:
        value = None
    return value # agora está fora do else

Ah, e reparou que vc usou == em vez de =? E fez isso em várias linhas (value == 2 quando deveria ser value = 2, etc). Enfim, a função correta ficaria assim:

def recieveActionLong(action):
    if action == 'create':
        value = 1
    elif action == 'read':
        value = 2
    elif action == 'update':
        value = 3
    elif action == 'delete':
        value = 4
    else:
        value = None
    return value

Se bem que também poderia ser assim:

def recieveActionLong(action):
    if action == 'create':
        return 1
    if action == 'read':
        return 2
    if action == 'update':
        return 3
    if action == 'delete':
        return 4
    return None

Afinal, o return encerra a função e não executa mais nada, então se entrar em um if, eu garanto que sairá da função e nem precisa do else.

E na segunda função, behaviors[action] or None não funciona caso a action não exista, pois aí dará um KeyError, pode testar. Para evitar isso, uma opção é trocar pelo método get, que em vez de lançar exceção, retorna None caso a chave não exista. Ou seja, ficaria assim:

def recieveActionsShort(action):
    behaviors = {
        'create': 1,
        'read': 2,
        'update': 3,
        'delete': 4
    }
    return behaviors.get(action)

Repare também que nem precisa da variável value, pode retornar direto. Agora vamos à questão em si (sobre qual é "melhor").


Qual é "melhor"?

Eu diria que depende. Como são poucas condições, me parece que tanto faz, o código nem fica tão mais curto assim (na minha opinião). Pelo menos, não tão mais curto que justifique criar um dicionário a cada execução da função. Apesar de ser pequeno, isso tem o seu custo. Vamos fazer um teste rápido com o módulo timeit:

def recieveActionLong(action):
    if action == 'create':
        return 1
    if action == 'read':
        return 2
    if action == 'update':
        return 3
    if action == 'delete':
        return 4
    return None

def recieveActionsShort(action):
    behaviors = {
        'create': 1,
        'read': 2,
        'update': 3,
        'delete': 4
    }
    return behaviors.get(action)

from timeit import timeit

action = 'create'
# executa 1 milhão de vezes cada função
params = { 'number' : 1000000, 'globals': globals() }
# imprime os tempos em segundos
print(timeit('recieveActionLong(action)', **params))
print(timeit('recieveActionsShort(action)', **params))

Os tempos são impressos em segundos e claro que varia conforme o hardware. Na minha máquina o resultado foi:

0.058050006002304144
0.13243731600232422

Ou seja, a versão mais curta é cerca de 2,2 vezes mais lenta.

É claro que se a função for executada poucas vezes, isso será imperceptível e desprezível. Mas é só pra dizer que a suposta "facilidade" não vem de graça, criar um dicionário a cada execução tem o seu custo e cabe a vc avaliar se faz ou não diferença no seu caso.


Uma vantagem que eu vejo na segunda abordagem é se o dicionário fosse um parâmetro da função:

def recieveActionsShort(action, behaviors):
    return behaviors.get(action)

action = 'read'
result = recieveActionsShort(action, { 'create': 1, 'read': 2, 'update': 3, 'delete': 4 })
print(result) # 2

# usando um grupo diferente de opções
result = recieveActionsShort(action, { 'read': 99, 'write': 88, 'append': 77 })
print(result) # 99

Dessa forma fica mais dinâmico e eu vejo uma justificativa maior para usar um dicionário. Se for um conjunto de opções fixas, não vejo tanto ganho assim. Se a quantidade de opções é muito grande, talvez valha a pena criar o dicionário apenas uma vez fora da função, por exemplo.

Mas aí o "melhor" depende muito do contexto. Código menor não é necessariamente melhor, muitas vezes a tentativa de escrever menos linhas pode deixá-lo confuso.

Carregando publicação patrocinada...
2

O que acha dessa forma?

action = 'read'
recieveActionsShort = lambda action: {'create': 1, 'read': 2, 'update': 3, 'delete': 4}.get(action, None)
value = recieveActionsShort(action)
print(value)

Nesse caso para poucos valores fica até bom colocar em apenas 1 linha usando função lambda do python. Mas acredito que perde na legibilidade.

3

Acho que fica menos legível, e continua com a desvantagem de gerar o dicionário toda hora.

Se quer mesmo usar o dicionário, poderia criar apenas uma vez. E aí pode até usar a opção que eu fiz, de passá-lo como parâmetro da função. Ou a função sempre usa o mesmo dicionário (usando global, que eu não gosto muito).

Na verdade, se a função faz só isso (apenas pega um dos valores), acho até que ela é desnecessária, use logo o dicionário e pronto. Só vejo necessidade da função se ela fizer algo a mais.

1

Essa era justamente uma abordagem que eu estava buscando discutir. Primeiramente eu realmente vacilei ao incluir '==' no lugar de '=', escrevi o código direito no editor de texto e não na IDE, então isso resultou nesse erro. Em seguida, realmente não coloquei o fator desempenho em questão, mas sim o fator legibilidade, nesse caso o 2º método é para if elifs que tenham muitos valores a serem testados, coloquei apenas 4 para facilitar a escrita. Por último a melhoria que você fez passando o dicionário é muito interessante. Obrigado pela contribuição, me ajudou muito.

1