Hướng dẫn is iterator faster than for loop python? - iterator có nhanh hơn vòng lặp for python không?

Các vòng lặp

>>> x, y = counts
0 của Python không hoạt động theo cách
>>> x, y = counts
0 Loops thực hiện trong các ngôn ngữ khác. Trong bài viết này, chúng tôi sẽ đi sâu vào các vòng lặp
>>> x, y = counts
0 của Python để xem cách chúng hoạt động dưới mui xe và lý do tại sao chúng làm việc theo cách chúng làm.

Show

Vòng lặp Gotchas

Chúng ta sẽ bắt đầu hành trình của mình bằng cách xem xét một số "gotchas". Sau khi chúng tôi tìm hiểu cách hoạt động vòng lặp trong Python, chúng tôi sẽ xem xét lại những gotchas này và giải thích những gì đang diễn ra.

Gotcha 1: Looping hai lần

Giả sử chúng ta có một danh sách các số và một trình tạo sẽ cung cấp cho chúng ta các bình phương của những con số đó:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

Chúng ta có thể chuyển đối tượng Trình tạo của mình cho hàm tạo

>>> x, y = counts
3 để tạo ra một bộ phận từ nó:

>>> tuple(squares)
(1, 4, 9, 25, 49)

Nếu sau đó chúng ta lấy cùng một đối tượng máy phát và chuyển nó đến hàm

>>> x, y = counts
4, chúng ta có thể hy vọng rằng chúng ta sẽ nhận được tổng số của các số này, sẽ là 88.

Thay vào đó chúng tôi nhận được

>>> x, y = counts
5.

Gotcha 2: Kiểm tra ngăn chặn

Hãy lấy cùng một danh sách các số và cùng một đối tượng máy phát:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

Nếu chúng tôi hỏi liệu

>>> x, y = counts
6 có nằm trong máy phát
>>> x, y = counts
7 của chúng tôi hay không, Python sẽ cho chúng tôi biết rằng 9 là trong
>>> x, y = counts
7. Nhưng nếu chúng ta hỏi một lần nữa, Python sẽ nói với chúng ta rằng 9 không phải trong
>>> x, y = counts
7.

>>> 9 in squares
True
>>> 9 in squares
False

Chúng tôi đã hỏi cùng một câu hỏi hai lần và Python đã cho chúng tôi hai câu trả lời khác nhau.

Gotcha 3: Giải nén

Từ điển này có hai cặp giá trị khóa:

>>> counts = {'apples': 2, 'oranges': 1}

Hãy giải nén từ điển này bằng nhiều bài tập:

>>> x, y = counts

Bạn có thể mong đợi rằng khi giải nén từ điển này, chúng tôi sẽ nhận được các cặp giá trị khóa hoặc có thể chúng tôi sẽ gặp lỗi.

Nhưng việc giải nén từ điển không gây ra lỗi và nó không trả về các cặp giá trị khóa. Khi bạn giải nén từ điển, bạn sẽ nhận được chìa khóa:

Chúng tôi sẽ quay lại với những gotchas này sau khi chúng tôi tìm hiểu một chút về logic cung cấp cho các đoạn python này.

Đánh giá: Python's for Loop

Python không có vòng lặp

>>> x, y = counts
0 truyền thống. Để giải thích những gì tôi muốn nói, chúng ta hãy xem một vòng lặp
>>> x, y = counts
0 trong một ngôn ngữ lập trình khác.

Đây là vòng lặp

>>> x, y = counts
0 kiểu C truyền thống được viết bằng JavaScript:

let numbers = [1, 2, 3, 5, 7];
for (let i = 0; i < numbers.length; i += 1) {
    print(numbers[i])
}

JavaScript, C, C ++, Java, PHP và cả một loạt các ngôn ngữ lập trình khác đều có loại vòng lặp

>>> x, y = counts
0 này. Nhưng Python thì không.does not.

Python không có vòng lặp

>>> x, y = counts
0 kiểu C truyền thống. Chúng tôi có một cái gì đó mà chúng tôi gọi là vòng lặp
>>> x, y = counts
0 trong Python, nhưng nó hoạt động giống như một vòng lặp foreach.does not have traditional C-style
>>> x, y = counts
0 loops. We do have something that we call a
>>> x, y = counts
0 loop in Python, but it works like a foreach loop.

Đây là hương vị của Python của

>>> x, y = counts
0 Loop:

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

Không giống như các vòng lặp

>>> x, y = counts
0 kiểu C truyền thống, các vòng lặp
>>> x, y = counts
0 của Python không có các biến chỉ mục. Không có chỉ mục khởi tạo, kiểm tra giới hạn hoặc tăng chỉ mục. Các vòng lặp
>>> x, y = counts
0 của Python thực hiện tất cả các công việc lặp lại danh sách

let numbers = [1, 2, 3, 5, 7];
for (let i = 0; i < numbers.length; i += 1) {
    print(numbers[i])
}

0 của chúng tôi cho chúng tôi.

Vì vậy, trong khi chúng tôi có

>>> x, y = counts
0 vòng lặp trong Python, chúng tôi không có vòng lặp
>>> x, y = counts
0 kiểu C truyền thống. Điều mà chúng ta gọi là một vòng lặp hoạt động rất khác nhau.

Định nghĩa: tererables và trình tự

Bây giờ chúng tôi đã giải quyết vòng lặp

>>> x, y = counts
0 không có chỉ mục trong phòng Python của chúng tôi, chúng ta hãy tránh xa một số định nghĩa.

Một điều đó là bất cứ điều gì bạn có thể lặp lại với một vòng lặp

>>> x, y = counts
0 trong Python. Iterables có thể được lặp qua, và bất cứ thứ gì có thể được lặp lại là một điều đáng tin cậy.iterable is anything you can loop over with a
>>> x, y = counts
0 loop in Python. Iterables can be looped over, and anything that can be looped over is an iterable.

>>> tuple(squares)
(1, 4, 9, 25, 49)

0

Trình tự là một loại rất phổ biến của có thể lặp lại. Danh sách, bộ dữ liệu và chuỗi là tất cả các chuỗi.

>>> tuple(squares)
(1, 4, 9, 25, 49)

1

Trình tự là lặp lại có một bộ tính năng cụ thể. Chúng có thể được lập chỉ mục bắt đầu từ

>>> x, y = counts
5 và kết thúc ở một ít hơn chiều dài của chuỗi, chúng có độ dài và chúng có thể được cắt lát. Danh sách, bộ dữ liệu, chuỗi và tất cả các chuỗi khác hoạt động theo cách này.

>>> tuple(squares)
(1, 4, 9, 25, 49)

2

Rất nhiều thứ trong Python là Iterables, nhưng không phải tất cả các vòng lặp đều là trình tự. Bộ, từ điển, tệp và trình tạo là tất cả các phép lặp nhưng không có thứ nào trong số này là chuỗi.

>>> tuple(squares)
(1, 4, 9, 25, 49)

3

Vì vậy, bất cứ điều gì có thể được lặp lại với một vòng lặp

>>> x, y = counts
0 đều có thể lặp lại, và các chuỗi là một loại có thể lặp lại, nhưng Python cũng có nhiều loại khác.

Python's cho các vòng lặp không sử dụng chỉ mục

Bạn có thể nghĩ rằng dưới các vòng lặp

>>> x, y = counts
0 của Hood Python sử dụng các chỉ mục để lặp. Ở đây chúng tôi theo cách thủ công trên một vòng lặp bằng cách sử dụng vòng lặp

let numbers = [1, 2, 3, 5, 7];
for (let i = 0; i < numbers.length; i += 1) {
    print(numbers[i])
}

8 và chỉ mục:

>>> tuple(squares)
(1, 4, 9, 25, 49)

4

Điều này hoạt động cho các danh sách, nhưng nó sẽ không hoạt động mọi thứ. Cách lặp này chỉ hoạt động cho các chuỗi.only works for sequences.

Nếu chúng ta cố gắng lặp thủ công qua một bộ bằng cách sử dụng các chỉ mục, chúng ta sẽ gặp lỗi:

>>> tuple(squares)
(1, 4, 9, 25, 49)

5

Các bộ không phải là trình tự, vì vậy chúng không hỗ trợ lập chỉ mục.

Chúng ta không thể lặp lại thủ công mọi điều khác nhau trong Python bằng cách sử dụng các chỉ mục. Điều này chỉ đơn giản là không hoạt động cho Iterables không phải là trình tự.

Công cụ lặp lại cho các vòng lặp

Vì vậy, chúng tôi đã thấy rằng các vòng ____60 của Python không được sử dụng các chỉ mục dưới mui xe. Thay vào đó, các vòng lặp

>>> x, y = counts
0 của Python sử dụng các trình lặp lại.iterators.

Tererators là những thứ cung cấp năng lượng cho Iterables. Bạn có thể nhận được một iterator từ bất kỳ điều đó. Và bạn có thể sử dụng một iterator để lặp thủ công trên các điều đó đến từ đó.

Hãy xem cách hoạt động của nó.

Dưới đây là ba lần lặp: một bộ, một tuple và một chuỗi.

>>> tuple(squares)
(1, 4, 9, 25, 49)

6

Chúng tôi có thể hỏi từng lần lặp lại cho một trình lặp lại bằng cách sử dụng hàm

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

1 tích hợp của Python. Truyền một hàm có thể cho chức năng

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

1 sẽ luôn cung cấp cho chúng tôi một trình lặp lại, bất kể loại khác mà chúng tôi đang làm việc.

>>> tuple(squares)
(1, 4, 9, 25, 49)

7

Khi chúng ta có một trình lặp, một điều chúng ta có thể làm với nó là lấy mục tiếp theo của nó bằng cách chuyển nó cho chức năng

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3 tích hợp.

>>> tuple(squares)
(1, 4, 9, 25, 49)

8

Trình lặp là trạng thái, có nghĩa là một khi bạn đã tiêu thụ một vật phẩm từ chúng, nó đã biến mất.

Nếu bạn yêu cầu mục

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3 từ trình lặp và không còn mục nào nữa, bạn sẽ nhận được ngoại lệ

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

5:

>>> tuple(squares)
(1, 4, 9, 25, 49)

9

Vì vậy, bạn có thể nhận được một iterator từ mọi thứ có thể. Điều duy nhất bạn có thể làm với Iterators là hỏi họ cho mục tiếp theo của họ bằng hàm

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3. Và nếu bạn chuyển chúng cho

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3 nhưng chúng không có mục tiếp theo, ngoại lệ

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

5 sẽ được nâng lên.

Bạn có thể nghĩ về các trình lặp như bộ phân phối PEZ không thể tải lại. Bạn có thể lấy Pez ra ngoài, nhưng một khi PEZ được gỡ bỏ, nó không thể được đặt lại, và một khi bộ phân phối trống, nó là vô dụng.

Vòng lặp mà không có vòng lặp

Bây giờ chúng tôi đã tìm hiểu về các chức năng của Iterators và

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

1 và

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3, chúng tôi sẽ cố gắng lặp thủ công một vòng lặp mà không cần sử dụng vòng lặp
>>> x, y = counts
0.

Chúng tôi sẽ làm như vậy bằng cách cố gắng biến vòng lặp

>>> x, y = counts
0 này thành vòng lặp

let numbers = [1, 2, 3, 5, 7];
for (let i = 0; i < numbers.length; i += 1) {
    print(numbers[i])
}

8:

0

Để làm điều này, chúng tôi sẽ:

  1. Lấy một người lặp từ đã có thể xác định được
  2. Nhiều lần nhận mục tiếp theo từ trình lặp
  3. Thực hiện thân máy của vòng
    >>> x, y = counts
    
    0 nếu chúng ta có thành công mục tiếp theo
  4. Dừng vòng lặp của chúng tôi nếu chúng tôi có ngoại lệ

    numbers = [1, 2, 3, 5, 7]
    for n in numbers:
        print(n)

    5 trong khi nhận được mục tiếp theo
1

Chúng tôi vừa phát minh lại một vòng lặp

>>> x, y = counts
0 bằng cách sử dụng vòng lặp và vòng lặp

let numbers = [1, 2, 3, 5, 7];
for (let i = 0; i < numbers.length; i += 1) {
    print(numbers[i])
}

8.

Mã ở trên khá nhiều định nghĩa cách vòng lặp hoạt động dưới mui xe trong Python. Nếu bạn hiểu cách các chức năng

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

1 và

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3 tích hợp hoạt động để lặp lại mọi thứ, bạn sẽ hiểu cách thức hoạt động của các vòng ____ ____60 của Python.

Trong thực tế, bạn sẽ hiểu nhiều hơn một chút so với cách

>>> x, y = counts
0 vòng lặp hoạt động trong Python. Tất cả các hình thức lặp qua vòng lặp hoạt động theo cách này.

Giao thức Iterator là một cách lạ mắt để nói "cách lặp qua Iterables hoạt động trong Python." Về cơ bản, đó là định nghĩa về cách thức hoạt động của

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

1 và ____993 hoạt động trong Python. Tất cả các dạng lặp trong Python được cung cấp bởi giao thức Iterator. iterator protocol is a fancy way of saying "how looping over iterables works in Python." It's essentially the definition of the way the

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

1 and

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3 functions work in Python. All forms of iteration in Python are powered by the iterator protocol.

Giao thức Iterator được sử dụng bởi các vòng lặp

>>> x, y = counts
0 (như chúng ta đã thấy):

2

Nhiều bài tập cũng sử dụng giao thức Iterator:

3

Biểu thức sao sử dụng giao thức Iterator:

4

Và nhiều chức năng tích hợp dựa trên giao thức Iterator:

5

Bất cứ điều gì trong Python hoạt động với một điều khác có thể sử dụng giao thức Iterator theo một cách nào đó. Bất cứ khi nào bạn lặp đi lặp lại trong Python, bạn đang dựa vào giao thức Iterator.

Máy phát điện là người lặp

Vì vậy, bạn có thể nghĩ: tererators có vẻ tuyệt vời, nhưng chúng cũng có vẻ như là một chi tiết triển khai và chúng tôi, vì người dùng của Python, có thể không cần phải quan tâm đến chúng.

Tôi có tin tức cho bạn: Rất phổ biến để làm việc trực tiếp với các trình lặp trong Python.

Đối tượng

>>> x, y = counts
7 ở đây là một trình tạo:

6

Và máy phát điện là trình lặp, có nghĩa là bạn có thể gọi

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3 trên trình tạo để nhận mục tiếp theo của nó:

7

Nhưng nếu bạn đã từng sử dụng một trình tạo trước đây, có lẽ bạn cũng biết rằng bạn cũng có thể lặp qua các trình tạo:

8

Nếu bạn có thể lặp lại một cái gì đó trong Python, thì đó là một điều không thể hiểu được.iterable.

Vì vậy, máy phát điện là máy lặp, nhưng máy phát điện cũng là Iterables. Những gì đang xảy ra ở đây?generators are iterators, but generators are also iterables. What's going on here?

tôi đã lừa dối bạn

Vì vậy, khi tôi giải thích cách các trình lặp hoạt động sớm hơn, tôi đã bỏ qua một chi tiết quan trọng về chúng.

Trình lặp là lặp lại.

Tôi sẽ nói một lần nữa: mọi trình lặp lại trong Python cũng là một điều có thể đi được, điều đó có nghĩa là bạn có thể lặp qua iterators.

Bởi vì trình lặp cũng là Iterables, bạn có thể nhận được một trình lặp từ trình lặp bằng cách sử dụng hàm

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

1 tích hợp:

9

Hãy nhớ rằng Iterables cung cấp cho chúng tôi các trình lặp lại khi chúng tôi gọi

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

1 trên chúng.

Khi chúng tôi gọi

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

1 trên trình lặp, nó sẽ luôn tự trả lại:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

0

Trình lặp là lặp lại và tất cả các trình lặp là trình lặp riêng của họ.

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

1

Bối rối chưa?

Hãy tóm tắt lại các điều khoản này.

  • Một điều không thể xảy ra là thứ bạn có thể lặp lạiable is something you're able to iterate over
  • Một iterator là tác nhân thực sự thực hiện việc lặp đi lặp lạiator is the agent that actually does the iterating over an iterable

Ngoài ra, trong Python Iterators cũng là người lặp lại và họ đóng vai trò là người lặp của riêng họ.

Vì vậy, các trình lặp là lặp đi lặp lại, nhưng chúng không có nhiều tính năng mà một số lần lặp có.

Trình lặp không có độ dài và chúng không thể được lập chỉ mục:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

2

Từ quan điểm của chúng tôi với tư cách là lập trình viên Python, những điều hữu ích duy nhất bạn có thể làm với trình lặp là chuyển nó cho chức năng

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3 tích hợp hoặc lặp qua nó:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

3

Và nếu chúng ta lặp lại một lần lặp lần thứ hai, chúng ta sẽ không nhận lại được gì:

Bạn có thể nghĩ về các trình lặp như những người lười biếng lười biếng sử dụng một lần, có nghĩa là chúng chỉ có thể được lặp lại trong một lần.lazy iterables that are single-use, meaning they can be looped over one time only.

Như bạn có thể thấy trong bảng sự thật bên dưới, Iterables không phải lúc nào cũng là người lặp nhưng trình lặp luôn luôn được lặp lại:

Sự vậtIterable?Iterator?
Có thể lặp lại
Người lặp lại

Người lặp lại

Máy phát điện

Danh sách

Iterators:

  • Giao thức lặp đầy đủ

Hãy xác định cách các trình lặp hoạt động theo quan điểm của Python.

  • Iterables có thể được chuyển đến hàm

    numbers = [1, 2, 3, 5, 7]
    for n in numbers:
        print(n)

    1 để lấy một trình lặp cho chúng.
  • Có thể được chuyển đến chức năng

    numbers = [1, 2, 3, 5, 7]
    for n in numbers:
        print(n)

    3, sẽ cung cấp cho mục tiếp theo của họ hoặc tăng ngoại lệ
  • Có thể được chuyển đến chức năng

    numbers = [1, 2, 3, 5, 7]
    for n in numbers:
        print(n)

    1 và sẽ trở lại

Nghịch đảo của các câu này cũng đúng:

Bất cứ điều gì có thể được chuyển cho numbers = [1, 2, 3, 5, 7]for n in numbers:     print(n)1 mà không có >>> tuple(squares)(1, 4, 9, 25, 49)26 là một

Bất cứ điều gì có thể được chuyển đến

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3 mà không có

>>> tuple(squares)
(1, 4, 9, 25, 49)

26 là một trình lặp lạilazy iterables that don't do any work until we ask them for their next item. Because we can create lazy iterables, we can make infinitely long iterables. And we can create iterables that are conservative with system resources, can save us memory, and can save us CPU time.

Bất cứ điều gì tự trả lại khi được chuyển đến numbers = [1, 2, 3, 5, 7]for n in numbers:     print(n)1 là một trình lặp lại

Đó là giao thức Iterator trong Python.

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

5

Tererators cho phép lười biếng

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

6

Trình lặp cho phép chúng tôi cả làm việc và tạo ra những thứ lười biếng không làm bất kỳ công việc nào cho đến khi chúng tôi yêu cầu họ cho mục tiếp theo của họ. Bởi vì chúng ta có thể tạo ra các vòng lặp lười biếng, chúng ta có thể tạo ra các vòng lặp dài vô hạn. Và chúng ta có thể tạo các vòng lặp bảo thủ với tài nguyên hệ thống, có thể tiết kiệm bộ nhớ của chúng ta và có thể tiết kiệm thời gian CPU của chúng ta.

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

7

Trình lặp ở khắp mọi nơi

Bạn đã thấy rất nhiều lần lặp trong Python. Tôi đã đề cập rằng máy phát điện là trình lặp lại. Nhiều lớp học tích hợp của Python cũng là trình lặp lại. Ví dụ, các đối tượng >>> tuple(squares)(1, 4, 9, 25, 49)30 và >>> tuple(squares)(1, 4, 9, 25, 49)31 của Python là trình lặp.

Trong Python 3,

>>> tuple(squares)
(1, 4, 9, 25, 49)

32,

>>> tuple(squares)
(1, 4, 9, 25, 49)

33 và

>>> tuple(squares)
(1, 4, 9, 25, 49)

34 đối tượng cũng là trình lặp.

Và các đối tượng tệp trong Python cũng là trình lặp.

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

8

Có rất nhiều trình lặp được tích hợp vào Python, trong thư viện tiêu chuẩn và trong các thư viện Python của bên thứ ba. Những người lặp này đều hoạt động như Lazy Iterables bằng cách trì hoãn công việc cho đến khi bạn yêu cầu họ cho mục tiếp theo của họ.

Tạo trình lặp của riêng bạn

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

9

Thật hữu ích khi biết rằng bạn đã sử dụng các trình lặp lại, nhưng tôi muốn bạn cũng biết rằng bạn có thể tạo các trình lặp của riêng bạn và các phép lặp lười biếng của riêng bạn.

>>> 9 in squares
True
>>> 9 in squares
False

0

Lớp này tạo ra một trình lặp lại chấp nhận một số số lượng và cung cấp hình vuông của từng số khi nó được lặp lại.

Nhưng sẽ không có công việc nào được thực hiện cho đến khi chúng ta bắt đầu lặp lại một trường hợp của lớp này.

Ở đây chúng tôi có một số ít có thể lặp lại vô hạn

>>> tuple(squares)
(1, 4, 9, 25, 49)

35 và bạn có thể thấy rằng

>>> tuple(squares)
(1, 4, 9, 25, 49)

36 chấp nhận

>>> tuple(squares)
(1, 4, 9, 25, 49)

35 mà không cần lặp lại hoàn toàn về điều này dài vô hạn này:

>>> 9 in squares
True
>>> 9 in squares
False

1

Lớp Iterator này hoạt động, nhưng chúng tôi thường không làm cho trình lặp lại theo cách này. Thông thường khi chúng tôi muốn tạo một trình lặp tùy chỉnh, chúng tôi tạo chức năng máy phát:

Hàm trình tạo này tương đương với lớp chúng tôi đã tạo ở trên và nó hoạt động về cơ bản theo cùng một cách.

Tuyên bố

>>> tuple(squares)
(1, 4, 9, 25, 49)

38 đó có thể có vẻ kỳ diệu, nhưng nó rất mạnh mẽ:

>>> tuple(squares)
(1, 4, 9, 25, 49)

38 cho phép chúng tôi đặt chức năng máy phát của chúng tôi tạm dừng giữa các cuộc gọi từ hàm

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3. Tuyên bố

>>> tuple(squares)
(1, 4, 9, 25, 49)

38 là thứ tách các chức năng của máy phát khỏi các chức năng thông thường.

Một cách khác, chúng tôi có thể thực hiện cùng một trình lặp này là với biểu thức máy phát.

Điều này làm điều tương tự như hàm máy phát của chúng tôi, nhưng nó sử dụng một cú pháp trông giống như một sự hiểu biết danh sách. Nếu bạn cần tạo ra một sự lười biếng trong mã của mình, hãy nghĩ về trình lặp và xem xét việc tạo chức năng máy phát điện hoặc biểu thức máy phát.

>>> 9 in squares
True
>>> 9 in squares
False

2

Cách lặp lại có thể cải thiện mã của bạn

>>> 9 in squares
True
>>> 9 in squares
False

3

Khi bạn đã chấp nhận ý tưởng sử dụng Lazy Iterables trong mã của mình, bạn sẽ thấy rằng có rất nhiều khả năng để khám phá hoặc tạo các chức năng trợ giúp hỗ trợ bạn lặp qua các phép lặp và xử lý dữ liệu.

Sự lười biếng và tổng kết

Sự lười biếng và thoát ra khỏi vòng lặp

Mã này in ra 10 dòng đầu tiên của tệp nhật ký:

>>> 9 in squares
True
>>> 9 in squares
False

4

Mã này cũng làm điều tương tự, nhưng chúng tôi đang sử dụng chức năng

>>> tuple(squares)
(1, 4, 9, 25, 49)

46 để chộp lấy 10 dòng đầu tiên của tệp khi chúng tôi lặp:

>>> 9 in squares
True
>>> 9 in squares
False

5

Biến

>>> tuple(squares)
(1, 4, 9, 25, 49)

47 mà chúng tôi đã thực hiện là một trình lặp lại. Một lần nữa, sử dụng một trình lặp lại cho phép chúng tôi đặt tên cho một cái gì đó (

>>> tuple(squares)
(1, 4, 9, 25, 49)

47) trước đây không được đặt tên. Đặt tên cho mọi thứ có thể làm cho mã của chúng tôi mô tả hơn và dễ đọc hơn.

Như một phần thưởng, chúng tôi cũng đã loại bỏ nhu cầu về tuyên bố

>>> tuple(squares)
(1, 4, 9, 25, 49)

49 trong vòng lặp của chúng tôi vì tiện ích

>>> tuple(squares)
(1, 4, 9, 25, 49)

50 xử lý việc phá vỡ cho chúng tôi.

Bạn có thể tìm thấy nhiều chức năng trợ giúp lặp hơn trong itertools trong thư viện tiêu chuẩn cũng như trong các thư viện của bên thứ ba như Boltons và nhiều iterTools hơn.

Tạo người trợ giúp lặp lại của riêng bạn

Bạn có thể tìm thấy các chức năng trợ giúp để lặp trong thư viện tiêu chuẩn và trong các thư viện của bên thứ ba, nhưng bạn cũng có thể tự làm!

Mã này tạo ra một danh sách các sự khác biệt giữa các giá trị liên tiếp theo một chuỗi.

>>> 9 in squares
True
>>> 9 in squares
False

6

Lưu ý rằng mã này có một biến bổ sung mà chúng ta cần gán mỗi lần chúng ta lặp. Cũng lưu ý rằng mã này chỉ hoạt động với những thứ chúng ta có thể cắt, như trình tự. Nếu

>>> tuple(squares)
(1, 4, 9, 25, 49)

51 là một trình tạo, đối tượng zip hoặc bất kỳ loại lặp khác, mã này sẽ không thành công.

Hãy viết một chức năng trợ giúp để sửa mã của chúng tôi.

Đây là một hàm trình tạo cung cấp cho chúng ta mục hiện tại và mục theo dõi nó cho mọi mục trong một số không thể tin được:

>>> 9 in squares
True
>>> 9 in squares
False

7

Chúng tôi theo cách thủ công một trình lặp từ có thể lặp lại, gọi

numbers = [1, 2, 3, 5, 7]
for n in numbers:
    print(n)

3 trên đó để lấy mục đầu tiên, sau đó lặp qua trình lặp lại của chúng tôi để lấy tất cả các mục tiếp theo, theo dõi mục cuối cùng của chúng tôi trên đường đi. Hàm này hoạt động không chỉ với các chuỗi, mà với bất kỳ loại khác.

Đây là cùng một mã như trước đây, nhưng chúng tôi đang sử dụng chức năng trợ giúp của mình thay vì theo dõi thủ công

>>> tuple(squares)
(1, 4, 9, 25, 49)

53:

>>> 9 in squares
True
>>> 9 in squares
False

8

Lưu ý rằng mã này không có bài tập khó xử cho

>>> tuple(squares)
(1, 4, 9, 25, 49)

53 treo xung quanh vòng lặp của chúng tôi. Chức năng máy phát

>>> tuple(squares)
(1, 4, 9, 25, 49)

55 xử lý công việc theo dõi

>>> tuple(squares)
(1, 4, 9, 25, 49)

53 cho chúng tôi.

Cũng lưu ý rằng mã này đã được nén đủ để chúng tôi thậm chí có thể sao chép theo cách của chúng tôi vào một danh sách hiểu nếu chúng tôi muốn.

>>> 9 in squares
True
>>> 9 in squares
False

9

Vòng lặp Gotchas được xem xét lại

Bây giờ chúng tôi đã sẵn sàng để quay trở lại những ví dụ kỳ lạ mà chúng tôi đã thấy trước đó và cố gắng tìm hiểu những gì đang xảy ra.

Gotcha 1: Làm cạn kiệt một người lặp

Ở đây chúng tôi có một đối tượng máy phát,

>>> x, y = counts
7:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

Nếu chúng tôi chuyển trình tạo này cho hàm tạo

>>> x, y = counts
3, chúng tôi sẽ lấy lại các mục của nó:

>>> counts = {'apples': 2, 'oranges': 1}
1

Nếu chúng ta cố gắng tính toán

>>> x, y = counts
4 của các số trong trình tạo này, chúng ta sẽ nhận được
>>> x, y = counts
5:

Máy phát điện này hiện đang trống: chúng tôi đã cạn kiệt nó. Nếu chúng ta cố gắng tạo ra một lần nữa, chúng ta sẽ nhận được một bộ phận trống:

Máy phát điện là người lặp. Và iterators là lặp lại sử dụng một lần. Chúng giống như các bộ phân phối Hello Kitty Pez không thể tải lại.

Gotcha 2: tiêu thụ một phần một trình lặp

Một lần nữa chúng tôi có một đối tượng máy phát,

>>> x, y = counts
7:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

Nếu chúng tôi hỏi liệu

>>> x, y = counts
6 có trong trình tạo
>>> x, y = counts
7 này hay không, chúng tôi sẽ nhận được

>>> tuple(squares)
(1, 4, 9, 25, 49)

64:

Nhưng nếu chúng ta hỏi lại câu hỏi tương tự, chúng ta sẽ nhận được

>>> tuple(squares)
(1, 4, 9, 25, 49)

65:

Khi chúng tôi hỏi liệu

>>> x, y = counts
6 có nằm trong trình tạo này không, Python phải lặp qua trình tạo này để tìm
>>> x, y = counts
6. Nếu chúng tôi tiếp tục lặp lại sau khi kiểm tra
>>> x, y = counts
6, chúng tôi sẽ chỉ nhận được hai số cuối cùng vì chúng tôi đã tiêu thụ các số trước thời điểm này:

>>> counts = {'apples': 2, 'oranges': 1}
7

Hỏi liệu một cái gì đó có chứa trong một iterator sẽ tiêu thụ một phần của iterator. Không có cách nào để biết liệu một cái gì đó nằm trong một trình lặp mà không bắt đầu lặp lại nó.

Gotcha 3: Giải nén là lặp đi lặp lại

Khi bạn lặp qua từ điển, bạn sẽ nhận được các phím:

>>> counts = {'apples': 2, 'oranges': 1}
8

Bạn cũng nhận được chìa khóa khi bạn giải nén một từ điển:

>>> counts = {'apples': 2, 'oranges': 1}
9

Vòng lặp phụ thuộc vào giao thức Iterator. Khả năng giải nén cũng dựa vào giao thức Iterator. Giải nén một từ điển thực sự giống như lặp lại từ điển. Cả hai đều sử dụng giao thức Iterator, vì vậy bạn nhận được kết quả tương tự trong cả hai trường hợp.

Tóm tắt lại và các tài nguyên liên quan

Trình tự là Iterables, nhưng không phải tất cả các vòng lặp đều là trình tự. Khi ai đó nói từ "có thể hiểu được", bạn chỉ có thể cho rằng họ có nghĩa là "một cái gì đó mà bạn có thể lặp lại." Đừng giả sử lặp lại có thể được lặp qua hai lần, yêu cầu độ dài của chúng hoặc được lập chỉ mục.

Trình lặp là hình thức lặp đi lặp lại thô sơ nhất trong Python. Nếu bạn muốn tạo ra một sự lười biếng trong mã của mình, hãy nghĩ về trình lặp và xem xét việc tạo chức năng máy phát điện hoặc biểu thức máy phát.

Và cuối cùng, hãy nhớ rằng mọi loại lặp trong Python đều dựa vào giao thức iterator, vì vậy hiểu giao thức Iterator là chìa khóa để hiểu khá nhiều về việc lặp lại trong Python nói chung.

Dưới đây là các bài viết và video liên quan tôi đề xuất:

  • Vòng lặp như một người bản địa, Ned Batchelder's Pycon 2013 Talk
  • Vòng lặp tốt hơn, bài nói chuyện này dựa trên
  • Giao thức Iterator: How

    >>> tuple(squares)
    (1, 4, 9, 25, 49)

    69 Loops hoạt động, một bài viết ngắn tôi đã viết trên giao thức Iterator
  • Sự hiểu biết có thể hiểu được, cuộc nói chuyện của tôi về sự hiểu biết và biểu thức máy phát
  • Python: Phạm vi không phải là người lặp, bài viết của tôi về phạm vi và trình lặp
  • Vòng lặp như một pro trong Python, DB's Pycon 2017 Talk

Bài viết này dựa trên Loop Better Talk mà tác giả đã đưa ra năm ngoái tại Djangocon Au, Pygotham và North Bay Python. Để có thêm nội dung như thế này, hãy tham dự PyCon, sẽ được tổ chức vào ngày 9 đến 17 tháng 5 năm 2018, tại Columbus, Ohio.

Iterator có nhanh hơn so với vòng lặp không?

Trình lặp. Để xác định xem nên sử dụng các vòng lặp hay trình lặp, bạn cần biết triển khai nào nhanh hơn: phiên bản của chức năng tìm kiếm với một vòng lặp rõ ràng hoặc phiên bản với trình lặp. Phiên bản lặp lại nhanh hơn một chút!The iterator version was slightly faster!

Có phải Iterators Python nhanh hơn?

Trình lặp sẽ nhanh hơn và có hiệu quả bộ nhớ tốt hơn.Chỉ cần nghĩ về một ví dụ về phạm vi (1000) so với xrange (1000)... Just think of an example of range(1000) vs xrange(1000) . (This has been changed in 3.0, range is now an iterator.) With range you pre-build your list, but xrange is an iterator and yields the next item when needed instead.

Điều gì nhanh hơn so với vòng lặp trong Python?

Một cách nhanh hơn để lặp trong Python là sử dụng các chức năng tích hợp.Trong ví dụ của chúng tôi, chúng tôi có thể thay thế vòng lặp cho chức năng tổng.Hàm này sẽ tổng hợp các giá trị bên trong phạm vi số.using built-in functions. In our example, we could replace the for loop with the sum function. This function will sum the values inside the range of numbers.

Sự khác biệt giữa Loop và Iterator trong Python là gì?

Khi một vòng lặp được thực thi, cho câu lệnh gọi iter () trên đối tượng, mà nó được cho là để lặp lại.Nếu cuộc gọi này thành công, cuộc gọi ITER sẽ trả về một đối tượng iterator xác định phương thức __next __ (), truy cập các phần tử của đối tượng cùng một lúc.