Що робить розуміння генератора? Як це працює? Я не міг знайти підручник про це.
Що робить розуміння генератора? Як це працює? Я не міг знайти підручник про це.
Відповіді:
Ви розумієте розуміння списку? Якщо так, вираз генератора схожий на розуміння списку, але замість того, щоб знайти всі цікавлять вас елементи та упакувати їх у список, він чекає і видає кожен елемент із виразу по одному.
>>> my_list = [1, 3, 5, 9, 2, 6]
>>> filtered_list = [item for item in my_list if item > 3]
>>> print(filtered_list)
[5, 9, 6]
>>> len(filtered_list)
3
>>> # compare to generator expression
...
>>> filtered_gen = (item for item in my_list if item > 3)
>>> print(filtered_gen) # notice it's a generator object
<generator object <genexpr> at 0x7f2ad75f89e0>
>>> len(filtered_gen) # So technically, it has no length
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'generator' has no len()
>>> # We extract each item out individually. We'll do it manually first.
...
>>> next(filtered_gen)
5
>>> next(filtered_gen)
9
>>> next(filtered_gen)
6
>>> next(filtered_gen) # Should be all out of items and give an error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> # Yup, the generator is spent. No values for you!
...
>>> # Let's prove it gives the same results as our list comprehension
...
>>> filtered_gen = (item for item in my_list if item > 3)
>>> gen_to_list = list(filtered_gen)
>>> print(gen_to_list)
[5, 9, 6]
>>> filtered_list == gen_to_list
True
>>>
Оскільки генератор виразу повинен видавати лише один елемент за раз, це може призвести до значної економії використання пам'яті. Вирази генератора мають найбільший сенс у сценаріях, коли потрібно брати по одному елементу за раз, робити багато обчислень на основі цього елемента, а потім переходити до наступного елемента. Якщо вам потрібно більше одного значення, ви також можете скористатися виразом генератора та взяти кілька за раз. Якщо вам потрібні всі значення до того, як ваша програма продовжить, використовуйте натомість розуміння списку.
next(...)
замість .__next__()
у Python 3.
If you need more than one value, you can also use a generator expression and grab a few at a time
. Не могли б ви навести приклад про це використання? Дякую.
Розуміння списку / генератора - це конструкція, за допомогою якої ви можете створити новий список / генератор із існуючого.
Скажімо, ви хочете сформувати список квадратів кожного числа від 1 до 10. Ви можете зробити це в Python:
>>> [x**2 for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
тут range(1,11)
генерує список [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
, але range
функція не є генератором до Python 3.0, а тому побудована мною конструкція є розумінням списку.
Якби я хотів створити генератор, який робить те саме, я міг би зробити це так:
>>> (x**2 for x in xrange(1,11))
<generator object at 0x7f0a79273488>
Однак у Python 3 range
є генератором, тому результат залежить лише від використовуваного вами синтаксису (квадратні дужки або круглі дужки).
Розуміння генератора - це простий спосіб створення генераторів з певною структурою. Скажімо, ви хочете, generator
щоб виводило одне за одним усі парні числа в your_list
. Якщо ви створите його за допомогою стилю функції, це буде так:
def allEvens( L ):
for number in L:
if number % 2 is 0:
yield number
evens = allEvens( yourList )
Ви могли б досягти того ж результату за допомогою цього виразу розуміння генератора:
evens = ( number for number in your_list if number % 2 == 0 )
В обох випадках, коли ви телефонуєте, next(evens)
ви отримуєте наступний парний номер your_list
.
Розуміння генератора - це підхід до створення ітерабелів, щось на зразок курсору, який рухається по ресурсу. Якщо ви знаєте курсор mysql або курсор mongodb, ви можете знати, що всі фактичні дані ніколи не завантажуються в пам'ять відразу, а по черзі. Курсор рухається вперед-назад, але в пам'яті завжди є один елемент рядка / списку.
Коротше кажучи, використовуючи розуміння генераторів, ви можете легко створити курсори в python.
Ще один приклад розуміння генератора:
print 'Generator comprehensions'
def sq_num(n):
for num in (x**2 for x in range(n)):
yield num
for x in sq_num(10):
print x