Qual é a definição mais básica de "iterável", "iterador" e "iteração" no Python?
Eu li várias definições, mas não consigo identificar o significado exato, pois ele ainda não se encaixa.
Alguém pode me ajudar com as 3 definições em termos leigos?
Qual é a definição mais básica de "iterável", "iterador" e "iteração" no Python?
Eu li várias definições, mas não consigo identificar o significado exato, pois ele ainda não se encaixa.
Alguém pode me ajudar com as 3 definições em termos leigos?
Respostas:
Iteração é um termo geral para pegar cada item de algo, um após o outro. Sempre que você usa um loop, explícito ou implícito, para examinar um grupo de itens, é iteração.
No Python, iterável e iterador têm significados específicos.
Um iterável é um objeto que possui um __iter__
método que retorna um iterador ou que define um __getitem__
método que pode receber índices seqüenciais começando do zero (e gera um IndexError
quando os índices não são mais válidos). Portanto, um iterável é um objeto do qual você pode obter um iterador .
Um iterador é um objeto com um método next
(Python 2) ou __next__
(Python 3).
Sempre que você usa um for
loop, ou map
uma compreensão de lista etc. no Python, o next
método é chamado automaticamente para obter cada item do iterador , passando pelo processo de iteração .
Um bom lugar para começar a aprender seria a seção de iteradores do tutorial e a seção de tipos de iteradores da página de tipos padrão . Depois de entender o básico, tente a seção de iteradores do HOWTO de Programação Funcional .
__len__
estaria necessariamente vinculado à iteração? Como saber o tamanho de algo o ajudaria a interagir com ele?
__getitem__
.
{'a': 'hi', 'b': 'bye'}
possui comprimento 2, mas não pode ser indexado por 0, 1 ou 2.
__iter__
método. Eu acho que jlh está se referindo a objetos iteráveis especificamente porque eles definem: "um __getitem__
método que pode receber índices seqüenciais a partir do zero".
Aqui está a explicação que eu uso nas aulas de Python:
Um ITERABLE é:
for x in iterable: ...
ouiter()
retornará um ITERATOR: iter(obj)
ou__iter__
que retorna um ITERATOR novo ou pode ter um __getitem__
método adequado para pesquisa indexada.Um ITERATOR é um objeto:
__next__
método que:
StopIteration
__iter__
método que retorna self
).Notas:
__next__
método no Python 3 está escrito next
no Python 2 enext()
chama esse método no objeto passado para ele.Por exemplo:
>>> s = 'cat' # s is an ITERABLE
# s is a str object that is immutable
# s has no state
# s has a __getitem__() method
>>> t = iter(s) # t is an ITERATOR
# t has state (it starts by pointing at the "c"
# t has a next() method and an __iter__() method
>>> next(t) # the next() function returns the next value and advances the state
'c'
>>> next(t) # the next() function returns the next value and advances
'a'
>>> next(t) # the next() function returns the next value and advances
't'
>>> next(t) # next() raises StopIteration to signal that iteration is complete
Traceback (most recent call last):
...
StopIteration
>>> iter(t) is t # the iterator is self-iterable
for
loops, e o primeiro marcador é sobre "looping over". Você poderia resolver estes?
iter()
" como "qualquer coisa que você pode passar para iter()
"
As respostas acima são ótimas, mas, como a maior parte do que eu vi, não enfatize distinção o suficiente para pessoas como eu.
Além disso, as pessoas tendem a ficar "muito pitonicas" colocando definições como "X é um objeto que possui __foo__()
método" antes. Tais definições estão corretas - elas se baseiam na filosofia de digitação de patos, mas o foco nos métodos tende a ficar mais claro quando se tenta entender o conceito em sua simplicidade.
Então eu adiciono minha versão.
Em linguagem natural,
Em Python,
iterável é um objeto que é, bem, iterável, que simplesmente coloca, significa que ele pode ser usado na iteração, por exemplo, com um for
loop. Quão? Usando o iterador . Eu vou explicar abaixo.
... enquanto o iterador é um objeto que define como realmente fazer a iteração - especificamente qual é o próximo elemento. É por isso que deve ter
next()
método.
Os iteradores também são iteráveis, com a distinção de que seu __iter__()
método retorna o mesmo objeto ( self
), independentemente de seus itens terem ou não sido consumidos por chamadas anteriores para next()
.
Então, o que o intérprete Python pensa quando vê uma for x in obj:
declaração?
Olha, um
for
laço. Parece um trabalho para um iterador ... Vamos pegar um. ... Tem esseobj
cara, então vamos perguntar a ele."Sr.
obj
, você tem seu iterador?" (... chamaiter(obj)
, que chamaobj.__iter__()
, que felizmente distribui um novo iterador brilhante_i
.)OK, foi fácil ... Vamos começar a iterar então. (
x = _i.next()
...x = _i.next()
...)
Como o Sr. obj
obteve sucesso neste teste (com um método retornando um iterador válido), recompensamos-o com o adjetivo: agora você pode chamá-lo de "Sr. iterável obj
".
No entanto, em casos simples, você normalmente não se beneficia de ter o iterador e iterável separadamente. Portanto, você define apenas um objeto, que também é seu próprio iterador. (O Python realmente não se importa com o fato de que a _i
distribuição obj
não foi tão brilhante, mas apenas a obj
própria).
É por isso que na maioria dos exemplos que eu vi (e o que estava me confundindo repetidamente), você pode ver:
class IterableExample(object):
def __iter__(self):
return self
def next(self):
pass
ao invés de
class Iterator(object):
def next(self):
pass
class Iterable(object):
def __iter__(self):
return Iterator()
Há casos, no entanto, quando você pode se beneficiar da separação do iterador do iterável, como quando você deseja ter uma linha de itens, mas mais "cursores". Por exemplo, quando você deseja trabalhar com os elementos "atual" e "próximo", é possível ter iteradores separados para ambos. Ou vários threads extraídos de uma lista enorme: cada um pode ter seu próprio iterador para percorrer todos os itens. Veja @ Raymond's e @ glglgl's respostas de acima.
Imagine o que você poderia fazer:
class SmartIterableExample(object):
def create_iterator(self):
# An amazingly powerful yet simple way to create arbitrary
# iterator, utilizing object state (or not, if you are fan
# of functional), magic and nuclear waste--no kittens hurt.
pass # don't forget to add the next() method
def __iter__(self):
return self.create_iterator()
Notas:
Vou repetir novamente: o iterador não é iterável . O iterador não pode ser usado como uma "fonte" no for
loop. O que o for
loop precisa principalmente é __iter__()
(que retorna algo com next()
).
Obviamente, esse for
não é o único loop de iteração; portanto, acima também se aplica a outras construções ( while
...).
O iterador next()
pode lançar StopIteration para interromper a iteração. No entanto, ele não precisa iterar para sempre ou usar outros meios.
No "processo de pensamento" acima, _i
ele realmente não existe. Eu inventei esse nome.
Há uma pequena alteração no Python 3.x: o next()
método (não o incorporado) agora deve ser chamado __next__()
. Sim, deveria ter sido assim o tempo todo.
Você também pode pensar assim: iterável possui os dados, o iterador puxa o próximo item
Isenção de responsabilidade: eu não sou desenvolvedor de nenhum intérprete Python, então não sei realmente o que o intérprete "pensa". As reflexões acima são apenas uma demonstração de como eu entendo o tópico de outras explicações, experimentos e experiências da vida real de um novato em Python.
for
loop precisa de um iterador ("Olha, um loop for. Parece um trabalho para um iterador ... Vamos pegar um."). Mas então você diz nas notas no final que "O iterador não pode ser usado como fonte em um for
loop" ...?
pass
o código para essas next
definições? Suponho que você apenas queira dizer que alguém precisa implementar uma maneira de obter a próxima, já que a próxima deve retornar alguma coisa.
pass
é para , depois de tudo.)
pass
, acho que está lá por razões sintáticas. Acabei de encontrar as respostas no objeto de reticências que são bastante interessantes: você pode usar ...
para indicar um bloco "todo mais tarde". NotImplemented
também está disponível.
for
loop '. Entendi a sua resposta e, caso contrário, gostaria, mas acho que se beneficiaria disso.
Um iterável é um objeto que possui um __iter__()
método. Ele pode ser repetido várias vezes, como list()
s e tuple()
s.
Um iterador é o objeto que itera. Ele é retornado por um __iter__()
método, retorna por meio de seu próprio __iter__()
método e possui um next()
método ( __next__()
na versão 3.x).
A iteração é o processo de chamar isso de next()
resp. __next__()
até que aumente StopIteration
.
Exemplo:
>>> a = [1, 2, 3] # iterable
>>> b1 = iter(a) # iterator 1
>>> b2 = iter(a) # iterator 2, independent of b1
>>> next(b1)
1
>>> next(b1)
2
>>> next(b2) # start over, as it is the first call to b2
1
>>> next(b1)
3
>>> next(b1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> b1 = iter(a) # new one, start over
>>> next(b1)
1
Iterable
.
Iterator
é sempre Iterable
e é seu Iterator
, duas chamadas de iter()
não dão necessariamente duas Iterator
s independentes .
Aqui está minha cábula:
sequence
+
|
v
def __getitem__(self, index: int):
+ ...
| raise IndexError
|
|
| def __iter__(self):
| + ...
| | return <iterator>
| |
| |
+--> or <-----+ def __next__(self):
+ | + ...
| | | raise StopIteration
v | |
iterable | |
+ | |
| | v
| +----> and +-------> iterator
| ^
v |
iter(<iterable>) +----------------------+
|
def generator(): |
+ yield 1 |
| generator_expression +-+
| |
+-> generator() +-> generator_iterator +-+
Quiz: Você vê como ...
__iter__()
método de pode ser implementado como um gerador?__next__
método não é necessariamente um iterador?Respostas:
__iter__
método Ter __iter__
é suficiente para ser iterável. Portanto, todo iterador é iterável.Quando __iter__
é chamado, ele deve retornar um iterador ( return <iterator>
no diagrama acima). Chamar um gerador retorna um iterador de gerador, que é um tipo de iterador.
class Iterable1:
def __iter__(self):
# a method (which is a function defined inside a class body)
# calling iter() converts iterable (tuple) to iterator
return iter((1,2,3))
class Iterable2:
def __iter__(self):
# a generator
for i in (1, 2, 3):
yield i
class Iterable3:
def __iter__(self):
# with PEP 380 syntax
yield from (1, 2, 3)
# passes
assert list(Iterable1()) == list(Iterable2()) == list(Iterable3()) == [1, 2, 3]
Aqui está um exemplo:
class MyIterable:
def __init__(self):
self.n = 0
def __getitem__(self, index: int):
return (1, 2, 3)[index]
def __next__(self):
n = self.n = self.n + 1
if n > 3:
raise StopIteration
return n
# if you can iter it without raising a TypeError, then it's an iterable.
iter(MyIterable())
# but obviously `MyIterable()` is not an iterator since it does not have
# an `__iter__` method.
from collections.abc import Iterator
assert isinstance(MyIterable(), Iterator) # AssertionError
__iter__
método. Você pode elaborar os pontos 2 e 3 editando esta resposta
__iter__()
retorna um iterador. Um gerador é um iterador, portanto, pode ser usado para essa finalidade. re 3 .: Só posso adivinhar aqui, mas acho que se __iter__()
está faltando ou não retorna self
, não é um iterador, porque o iterador __iter__()
precisa retornar self
.
Não sei se ajuda alguém, mas sempre gosto de visualizar conceitos na minha cabeça para melhor entendê-los. Então, como eu tenho um filho pequeno, visualizo o conceito iterável / iterador com tijolos e papel branco.
Suponha que estejamos no quarto escuro e no chão tenhamos tijolos para o meu filho. Tijolos de diferentes tamanhos, cores, não importam agora. Suponha que tenhamos 5 tijolos como esses. Esses 5 tijolos podem ser descritos como um objeto - digamos, kit de tijolos . Podemos fazer muitas coisas com este kit de tijolos - podemos pegar um e depois o segundo e o terceiro, trocar de lugar dos tijolos, colocar o primeiro tijolo acima do segundo. Podemos fazer muitos tipos de coisas com elas. Portanto, este kit de tijolos é um objeto ou sequência iterável , pois podemos percorrer cada tijolo e fazer algo com ele. Só podemos fazer isso como meu filho pequeno - podemos brincar com um tijolo de cada vez, . Então, novamente, eu me imagino este kit de tijolos para ser umiterável .
Agora lembre-se de que estamos no quarto escuro. Ou quase escuro. O fato é que não vemos claramente esses tijolos, que cor são, que forma etc. Portanto, mesmo se queremos fazer algo com eles - também conhecido como iterar através deles - não sabemos realmente o que e como, porque é muito escuro.
O que podemos fazer é próximo ao primeiro tijolo - como elemento de um kit de tijolos -, podemos colocar um pedaço de papel branco fluorescente para vermos onde está o primeiro elemento de tijolo. E cada vez que tiramos um tijolo de um kit, substituímos o pedaço de papel branco por outro próximo para poder vê-lo no quarto escuro. Este pedaço de papel branco não passa de um iterador . É um objeto também . Mas um objeto com o que podemos trabalhar e brincar com elementos do nosso iterável objeto - kit de tijolos.
A propósito, isso explica meu erro inicial quando tentei o seguinte em um IDLE e obtive um TypeError:
>>> X = [1,2,3,4,5]
>>> next(X)
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
next(X)
TypeError: 'list' object is not an iterator
A lista X aqui era o nosso kit de tijolos, mas NÃO era um pedaço de papel branco. Eu precisava encontrar um iterador primeiro:
>>> X = [1,2,3,4,5]
>>> bricks_kit = [1,2,3,4,5]
>>> white_piece_of_paper = iter(bricks_kit)
>>> next(white_piece_of_paper)
1
>>> next(white_piece_of_paper)
2
>>>
Não sei se ajuda, mas me ajudou. Se alguém pudesse confirmar / corrigir a visualização do conceito, ficaria agradecido. Isso me ajudaria a aprender mais.
Iterável : - algo que é iterável é iterável; como seqüências como listas, strings, etc. Também possui o __getitem__
método ou um __iter__
método. Agora, se usarmos a iter()
função nesse objeto, obteremos um iterador.
Iterador : - Quando obtemos o objeto iterador da iter()
função; chamamos __next__()
método (em python3) ou simplesmente next()
(em python2) para obter os elementos um a um. Essa classe ou instância dessa classe é chamada de iterador.
Dos documentos: -
O uso de iteradores permeia e unifica o Python. Nos bastidores, a instrução for chama iter()
o objeto contêiner. A função retorna um objeto iterador que define o método __next__()
que acessa elementos no contêiner, um de cada vez. Quando não há mais elementos, __next__()
gera uma exceção StopIteration que informa ao loop for para terminar. Você pode chamar o __next__()
método usando a next()
função interna; este exemplo mostra como tudo funciona:
>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration
Ex de uma classe: -
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
... print(char)
...
m
a
p
s
Eu não acho que você pode simplificar muito mais que a documentação , no entanto, tentarei:
Você pode pensar no Iterator como um pseudo-método auxiliar (ou pseudo-atributo) que fornece (ou retém) o próximo (ou primeiro) item no iterável . (Na prática, é apenas um objeto que define o método next()
)
A iteração é provavelmente melhor explicada pela definição Merriam-Webster da palavra :
b: a repetição de uma sequência de instruções do computador um número especificado de vezes ou até que uma condição seja atendida - compare a recursão
iterable = [1, 2]
iterator = iter(iterable)
print(iterator.__next__())
print(iterator.__next__())
tão,
iterable
é um objeto que pode ser repetido . por exemplo, lista, string, tupla etc.
usar a iter
função em nosso iterable
objeto retornará um objeto iterador.
agora esse objeto iterador possui um método chamado __next__
(no Python 3 ou apenas next
no Python 2) pelo qual você pode acessar cada elemento do iterável.
portanto, a SAÍDA DO CÓDIGO ACIMA SERÁ:
1
2
Os iteráveis têm um
__iter__
método que instancia um novo iterador sempre.Os iteradores implementam um
__next__
método que retorna itens individuais e um__iter__
método que retornaself
.Portanto, os iteradores também são iteráveis, mas iterables não são iteradores.
Luciano Ramalho, Python Fluente.
Antes de lidar com os iteráveis e o iterador, o principal fator que decide o iterável e o iterador é a sequência
Sequência: Sequência é a coleta de dados
Iterável: Iterável é o objeto do tipo sequência que suporta o __iter__
método.
Método Iter: o método Iter toma a sequência como uma entrada e cria um objeto que é conhecido como iterador
Iterador: Iterador é o objeto que chama o próximo método e transversal através da sequência. Ao chamar o próximo método, ele retorna o objeto que ele atravessou atualmente.
exemplo:
x=[1,2,3,4]
x é uma sequência que consiste na coleta de dados
y=iter(x)
Ao chamar, iter(x)
ele retorna um iterador apenas quando o objeto x tem o método iter, caso contrário, gera uma exceção.Se ele retorna o iterador, y é atribuído assim:
y=[1,2,3,4]
Como y é um iterador, portanto, ele suporta next()
método
Ao chamar o próximo método, ele retorna os elementos individuais da lista, um por um.
Depois de retornar o último elemento da sequência, se chamarmos novamente o próximo método, gera um erro StopIteration
exemplo:
>>> y.next()
1
>>> y.next()
2
>>> y.next()
3
>>> y.next()
4
>>> y.next()
StopIteration
No Python, tudo é um objeto. Quando se diz que um objeto é iterável, significa que você pode percorrer (ou seja, iterar) o objeto como uma coleção.
Matrizes, por exemplo, são iteráveis. Você pode percorrê-los com um loop for e passar do índice 0 ao índice n, sendo n o comprimento do objeto da matriz menos 1.
Dicionários (pares de chave / valor, também chamados de matrizes associativas) também são iteráveis. Você pode percorrer as chaves deles.
Obviamente, os objetos que não são coleções não são iteráveis. Um objeto bool, por exemplo, tem apenas um valor, Verdadeiro ou Falso. Não é iterável (não faria sentido que seja um objeto iterável).
Consulte Mais informação. http://www.lepus.org.uk/ref/companion/Iterator.xml
iter()
os tipos de coleção padrão são iteráveis, mas não são coleções em si.
collections.abc.AsyncIterator
testes para__aiter__
e__anext__
métodos. Esta é uma nova adição no 3.6.