segunda-feira, 18 de janeiro de 2010

Equívocos II

Existem dois métodos que se aplicam a dicionários que, por serem semelhantes, levam a alguns erros. São setdefault e get. Para explicitar as diferenças vamos considerar um exemplo concreto. Admitamos que estamos a fazer o índice de um livro, isto é queremos associar a cada palavra a indicação das páginas do livro onde essa palavra ocorre. Vamos usar um dicionário para guardar esta associação. Suponhamos que queremos implementar o método que acrescenta uma palavra (e a respectiva página) ao índice. Uma solução trivial seria:

def add_palavra_triv(indice,palavra,pagina):
if palavra in indice:
indice[palavra].append(pagina)
else:
indice[palavra] = [pagina]

Note-se que não é preciso fazer if palavra in indice.keys(). Atente-se ainda no modo distinto como temos que tratar o caso de a palavra estar, ou não, no dicionário. O leitor mais conhecedor de Python pode saber que é possível fazer tudo sem precisar do teste, e achar que usar o setdefault ou o get é o mesmo. Propõe por isso duas soluções alternativas:

def add_palavra_get(indice,palavra, pagina):
indice.get(palavra,[]).append(pagina)

def add_palavra_set(indice,palavra, pagina):
indice.setdefault(palavra,[]).append(pagina)

Mas, para sua surpresa, se executar o código seguinte o resultado não é bem o que estava à espera.

>>> dic = {'eu':[1,5,7], 'tu': [2,4,7]}
>>> add_palavra_get(dic, 'eu', 10)
>>> add_palavra_get(dic, 'ele', 20)
>>> print dic
{'eu': [1, 5, 7, 10], 'tu': [2, 4, 7]}
>>> add_palavra_set(dic,'tu', 8)
>>> add_palavra_set(dic,'ele', 33)
>>> print dic
{'eu': [1, 5, 7, 10], 'tu': [2, 4, 7, 8], 'ele': [33]}

Fica claro que no caso em que a chave não está no dicionário os dois métodos são diferentes: enquanto setdefault acrescenta o novo par, o mesmo não acontece com o método get.

Podemos definir como regra que sempre que os valores forem objectos mutáveis deve preferir setdefault. Caso se tratem de objectos imutáveis deve optar por get. Por exemplo, se o que pretende é apenas contar quantas vezes uma palavra ocorre num texto, deve usar:


indice[palavra] = indice.get(palavra,0) + 1

Sem comentários:

Enviar um comentário