Estou pesquisando em uma base de código contendo milhares de ocorrências de foo in list(bar)
, por exemplo:
- como uma expressão booleana:
if foo in list(bar) or ...:
...
- em um loop for:
for foo in list(bar):
...
- em uma expressão geradora:
",".join(str(foo) for foo in list(bar))
Existe um cenário (como uma versão dada do Python, um comportamento conhecido com um verificador de tipos, etc...) onde foo in list(bar)
não é apenas uma versão de foo in bar
? O que estou esquecendo aqui?
Às vezes eu fiz/vi isso quando
bar
fui modificado no loop, por exemplo:Com sua substituição, isso aumenta
RuntimeError: Set changed size during iteration
.Tente isso online!
Um exemplo da biblioteca padrão do Python
Dezenas de outros (muitos feitos pelo motivo acima, mas não todos).
Aqui faz a diferença:
Isso imprime uma linha vazia. Com sua substituição, ele imprime
a r
em vez disso.Tente isso online!
Se
foo
ebar
forem ambas strings , os testes de associação se comportam de forma diferente.<str> in <str>
verifica substrings enquanto<str> in list(<str>)
verifica caracteres .Em relação ao looping, não se deixe enganar pela sintaxe, não é o mesmo que a expressão booleana. O looping usa o protocolo iterável (como
__iter__
), enquanto a expressão booleana usa o protocolo de teste de associação (como__contains__
, ou ele retorna ao protocolo iterável)Então, qualquer um poderia criar um tipo que funcionasse desta maneira:
A maioria dos tipos internos são "bem comportados". No entanto, uma exceção importante é provavelmente
str
e outros tipos semelhantes (bytes
,bytearray
):Além disso, para pelo menos uma biblioteca popular,
numpy
esse não é o caso:Quando
bar
é um gerador,bar
elist(bar)
pode ter outras diferenças. Aqui está um exemplo:No primeiro caso,
if foo in abc()
não esgota o gerador. Devido à avaliação preguiçosa, uma vez que'a'
é produzido, o gerador não produzirá mais itens.No segundo caso,
if foo in list(abc())
exaure o gerador, o que levanta uma exceção. Então'with list()'
nunca é impresso.