2013-05-10 40 views
55

Tôi đang tìm mã để quay con trỏ trong thiết bị đầu cuối và tìm thấy điều này. Tôi đã tự hỏi điều gì đã xảy ra trong đoạn mã. Cụ thể là for c in spinning_cursor(): Tôi chưa từng thấy cú pháp này. Có phải vì tôi đang trả lại một phần tử từ một trình tạo tại một thời điểm với yield và điều này được gán cho c? Bất kỳ ví dụ khác về điều này cho x trong y() sử dụng?cho x trong y(): làm thế nào để làm việc này?

import sys 
import time 

def spinning_cursor(): 
    cursor='/-\|' 
    i = 0 
    while 1: 
     yield cursor[i] 
     i = (i + 1) % len(cursor) 

for c in spinning_cursor(): 
    sys.stdout.write(c) 
    sys.stdout.flush() 
    time.sleep(0.1) 
    sys.stdout.write('\b') 
+2

Ví dụ khác? cho i trong phạm vi (10): in (i) – antoyo

+0

bạn có thể tìm thấy mọi thứ chỉ ở đây: http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained – pylover

+0

Một ví dụ khác về cách hiệu suất hoạt động với một chức năng ở đây ... Tôi không cần một ví dụ bây giờ mà tôi hiểu. Ngoài ra, cảm ơn @pylover – Paul

Trả lời

38

Sử dụng yield chuyển chức năng thành generator. Máy phát điện là loại chuyên dụng của iterator. for luôn lặp qua vòng lặp, lần lượt lấy từng phần tử và gán nó cho (các) tên bạn liệt kê.

spinning_cursor() trả về trình tạo, mã bên trong spinning_cursor() không thực sự chạy cho đến khi bạn bắt đầu lặp qua trình tạo. Lặp lại trên một máy phát có nghĩa là mã trong hàm được thực thi cho đến khi nó đi qua một câu lệnh yield, tại thời điểm đó kết quả của biểu thức được trả về như giá trị tiếp theo và thực thi được tạm dừng một lần nữa.

Vòng for thực hiện điều đó, nó sẽ gọi tương đương next() trên máy phát, cho đến khi tín hiệu máy phát được thực hiện bằng cách tăng StopIteration (điều này xảy ra khi hàm trả về). Mỗi giá trị trả về của next() được gán, lần lượt, đến c.

Bạn có thể thấy điều này bằng cách tạo ra các máy phát điện trên trong dấu nhắc Python:

>>> def spinning_cursor(): 
...  cursor='/-\|' 
...  i = 0 
...  while 1: 
...   yield cursor[i] 
...   i = (i + 1) % len(cursor) 
... 
>>> sc = spinning_cursor() 
>>> sc 
<generator object spinning_cursor at 0x107a55eb0> 
>>> next(sc) 
'/' 
>>> next(sc) 
'-' 
>>> next(sc) 
'\\' 
>>> next(sc) 
'|' 

máy phát điện cụ thể này không bao giờ trở lại, vì vậy StopIteration không bao giờ lớn lên và for vòng lặp sẽ tiếp tục mãi mãi, trừ khi bạn giết kịch bản.

+5

Waaaay quá nhanh. – pcalcao

+0

Cảm ơn Martijn. Ý tưởng là gọi một hàm và trong khi nó đang xử lý, hiển thị con trỏ quay này. Khi nó được xử lý xong nó sẽ bị dừng lại. Vì vậy, tôi sẽ làm việc trên đó. Cảm ơn câu trả lời tuyệt vời. – Paul

2

hàm spinning_cursor trả về một lần lặp (máy phát từ năng suất).

for c in spinning_cursor(): 

sẽ được giống như

for i in [1, 2, 3, 4]: 
4

Trong Python, câu lệnh for cho phép bạn duyệt qua các yếu tố.

Theo các documentation:

Python cho lặp tuyên bố trên các mục của bất kỳ chuỗi (một danh sách hoặc một chuỗi), theo thứ tự mà chúng xuất hiện trong chuỗi

Ở đây, phần tử sẽ là giá trị trả về của spinning_cursor().

3

Cú pháp for c in spinning_cursor() là vòng lặp for-each. Nó sẽ lặp qua từng mục trong trình lặp được trả về bởi spinning_cursor().

Bên trong vòng lặp sẽ:

  1. Viết nhân vật đạt tiêu chuẩn ra và tuôn ra nên nó sẽ hiển thị.
  2. Ngủ cho một phần mười giây thứ hai
  3. Viết \b, được hiểu là không gian ẩn (xóa ký tự cuối cùng).Chú ý điều này xảy ra ở phần cuối của vòng lặp vì vậy nó sẽ không được viết trong phiên đầu tiên, và nó chia sẻ cuộc gọi tuôn ra ở bước 1.

spinning_cursor() sẽ trả về một generator, mà không làm thực sự chạy cho đến khi bạn bắt đầu lặp lại. Dường như nó sẽ lặp qua '/-\|', theo thứ tự, mãi mãi. Nó giống như có một danh sách vô hạn để lặp qua.

Vì vậy, đầu ra cuối cùng sẽ trở thành một spinner ASCII. Bạn sẽ thấy các ký tự này (trong cùng một vị trí) lặp lại cho đến khi bạn giết tập lệnh.

/ 
- 
\ 
| 
2

Martijn Pieters giải thích là tuyệt vời. Dưới đây là một triển khai khác của cùng mã mà bạn có trong câu hỏi. nó sử dụng itertools.cycle để tạo ra kết quả tương tự như spinning_cursor. itertools được làm đầy với các ví dụ tuyệt vời của các trình vòng lặp và các hàm để giúp tạo các trình vòng lặp của riêng bạn. Nó có thể giúp bạn hiểu trình vòng lặp tốt hơn.

import sys, time, itertools 

for c in itertools.cycle('/-\|'): 
    sys.stdout.write(c) 
    sys.stdout.flush() 
    time.sleep(0.1) 
    sys.stdout.write('\b') 
+0

Công cụ tuyệt vời cảm ơn bạn. – Paul