2012-05-03 40 views
7

Gần đây tôi đã bắt đầu học Python, và khái niệm về vòng lặp vẫn còn hơi khó hiểu đối với tôi. Tôi hiểu rằng nó thường theo định dạng for x in y, trong đó y chỉ là một số danh sách.Đối với vòng lặp (người mới)

Các for-each loop for (int n: someArray) trở thành for n in someArray,

Và vòng lặp for for (i = 0; i < 9; i-=2) có thể được đại diện bởi for i in range(0, 9, -2)

Giả sử thay vì một tăng liên tục, tôi muốn i*=2, hoặc thậm chí i*=i. Điều này có thể, hoặc tôi sẽ phải sử dụng một vòng lặp while thay thế?

+0

'for i in range (0,9, -2)' sẽ không lặp lại nếu số đầu tiên nếu nhỏ hơn số thứ hai. – hexparrot

+0

Chính xác hơn, dải ô() không thể cung cấp mảng có bước âm cho giá trị dương. Đó là một vòng lặp vô hạn. – dwerner

+0

@ user1320925 bạn có muốn các giá trị này là các giá trị của i: 1 2, 4, 8, 16, 32 .... –

Trả lời

1

Bạn sẽ muốn sử dụng list comprehensions cho

print [x**2 for x in xrange(10)] # X to the 2nd power. 

print [x**x for x in xrange(10)] # X to the Xth power. 

Cú pháp danh sách hiểu đây là một sau:

[EXPRESSION for VARIABLE in ITERABLE if CONDITION] 

Dưới mui xe, nó hoạt động tương tự như map and filter function:

def f(VARIABLE): return EXPRESSION 
def c(VARIABLE): return CONDITION 

filter(c, map(f, ITERABLE)) 

Ví dụ đưa ra:

def square(x): return x**2 

print map(square, xrange(10)) 

def hypercube(x): return x**x 

print map(hypercube, xrange(10)) 

Mà có thể được sử dụng như phương pháp thay thế nếu bạn don' t như danh sách comprehensions. Bạn cũng có thể sử dụng vòng lặp for, nhưng điều đó sẽ không còn là thành ngữ Python ...

+0

Tạo một danh sách và sau đó lặp lại nó không phải là tối ưu, và đó không phải là cú pháp cho một danh sách comp (đó là một biểu thức, không phải là một hàm, nó có thể lặp lại, không phải danh sách, và có thể có một câu lệnh if ở cuối). –

+0

@Lattyware: Tối ưu, đó là biểu thức của trình tạo. Lưu ý cách câu trả lời của bạn liên kết đến việc hiểu danh sách ...;) –

+0

Không đúng sự thật. Câu trả lời của tôi liên kết đến một video mà tôi đã thực hiện giải thích sự hiểu biết danh sách cùng với các biểu thức máy phát và dict và thiết lập hiểu. Biểu thức máy phát điện là lười biếng, và do đó ** rất ** khác với một danh sách hiểu. Nếu chúng ta thực hiện một vòng lặp đến năm triệu, giải pháp của bạn sẽ tạo một danh sách từ '0 * 2' đến '4999999 * 2', sau đó lặp lại nó. Một biểu thức máy phát điện sẽ tính toán chúng khi cần thiết. –

11

Như bạn nói, một vòng lặp for lặp qua các phần tử của danh sách. Danh sách có thể chứa bất kỳ thứ gì bạn thích, vì vậy bạn có thể xây dựng danh sách trước có chứa từng bước.

Vòng lặp for cũng có thể lặp qua một số "generator", đây là một đoạn mã nhỏ thay vì danh sách thực tế. Trong Python, range() thực sự là một máy phát điện (trong Python 2.x mặc dù, range() trả về một danh sách trong khi xrange() là máy phát điện).

Ví dụ:

def doubler(x): 
    while True: 
     yield x 
     x *= 2 

for i in doubler(1): 
    print i 

Các for vòng lặp trên sẽ in

1 
2 
4 
8 

và như vậy, cho đến khi bạn nhấn Ctrl + C.

+0

Tôi sẽ nói rằng một máy phát điện độc lập là quá mức cần thiết cho điều này - một biểu hiện máy phát điện có thể sẽ làm điều đó chỉ là tốt. Ví dụ: 'cho i trong (x * 2 cho x trong phạm vi (10)):' –

+1

Có, bạn có thể viết mã nhỏ gọn hơn. Tuy nhiên, tôi nghĩ rằng đó là hướng dẫn để cho thấy một hương vị của những gì một máy phát điện tổng quát có thể làm. –

+0

Mặc dù thật tuyệt khi biết bạn có thể làm được nhiều hơn với nó, nhưng không tốt để khuyên mọi người làm quá nhiều thứ. Giải thích cú pháp biểu thức trình tạo cũng có thể là tốt, để tránh việc gửi người hỏi làm cho các máy tạo rất đơn giản như là các hàm đầy đủ. –

8

Bạn có thể sử dụng một generator expression để làm điều này một cách hiệu quả và với ít mã dư thừa:

for i in (2**x for x in range(10)): #In Python 2.x, use `xrange()`. 
    ... 

biểu Generator làm việc giống như việc xác định một máy phát điện bằng tay (như trong Greg Hewgill's answer), với một cú pháp tương tự như một sự hiểu biết danh sách. Chúng được đánh giá một cách lười biếng - có nghĩa là chúng không tạo ra một danh sách khi bắt đầu hoạt động, điều này có thể gây ra hiệu suất tốt hơn nhiều trên các vòng lặp lớn. Vì vậy, máy phát điện này hoạt động bằng cách chờ cho đến khi nó được yêu cầu cho một giá trị, sau đó yêu cầu range(10) cho một giá trị, tăng gấp đôi giá trị đó và chuyển nó trở lại vòng lặp for. Nó làm điều này nhiều lần cho đến khi máy phát điện range() không mang lại nhiều giá trị hơn.

+2

@TomWijsman Tôi không nghĩ nó dễ đọc hơn. Nếu bạn thực sự muốn bạn có thể làm 'tăng gấp đôi = (x * 2 cho x trong phạm vi (10))' và sau đó lặp qua 'tăng gấp đôi'. Nếu bạn so sánh nó với câu trả lời của bạn - một sự hiểu biết danh sách - chúng ta đang nói về các dấu ngoặc khác nhau bên ngoài biểu thức. Làm thế nào là ít có thể đọc được hoặc duy trì? –

+2

@TomWijsman Câu trả lời của tôi là một lớp lót - và gợi ý rằng một dòng đơn luôn luôn tốt hơn nhiều dòng là điên. Đôi khi nhiều dòng hơn có thể đọc được. Để gỡ lỗi trở nên khó khăn hơn, điều đó đơn giản là không đúng sự thật. Như tôi đã nói trong bình luận khác của tôi - có một lý do tại sao tất cả các nội trang của Python 3 bây giờ là lười biếng trong 2.x họ tạo ra các danh sách. –

+1

@Lattyware Tôi nghĩ rằng OP muốn 2,4,8,16,32 ... và giải pháp của bạn cho 2,4,6,8,10 .... –

5

Hãy nhớ rằng phần 'danh sách' của Python có thể là bất kỳ chuỗi lặp nào.

Ví dụ:

Một chuỗi:

for c in 'abcdefg': 
    # deal with the string on a character by character basis... 

Một file:

with open('somefile','r') as f: 
    for line in f: 
     # deal with the file line by line 

Một từ điển:

d={1:'one',2:'two',3:'three'} 
for key, value in d.items(): 
    # deal with the key:value pairs from a dict 

Một lát một danh sách:

012.351.
l=range(100) 
for e in l[10:20:2]: 
    # ever other element between 10 and 20 in l 

etc etc etc etc

Vì vậy, nó thực sự là sâu sắc hơn rất nhiều so với 'chỉ là một số danh sách'

Như những người khác đã nói, chỉ cần đặt các iterable được những gì bạn muốn nó được cho bạn câu hỏi ví dụ:

for e in (i*i for i in range(10)): 
    # the squares of the sequence 0-9... 

l=[1,5,10,15] 
for i in (i*2 for i in l): 
    # the list l as a sequence * 2... 
+0

+1 - Đây là một điểm tốt. Đối với các vòng lặp qua bất kỳ danh sách lặp lại nào, không chỉ là danh sách. –

+0

Tôi không thấy cách này trả lời câu hỏi. –

+0

@Tom Wijsman: OP nói rằng 'khái niệm về vòng lặp vẫn còn hơi khó hiểu đối với tôi. Tôi hiểu rằng nó thường theo định dạng cho x trong y, trong đó y chỉ là một số danh sách.' Tôi đã làm rõ rằng y là nhiều hơn 'chỉ một số danh sách' –

0

Chỉ cần cho một sự thay thế, làm thế nào về khái quát hóa các hoạt động lặp/increment để một hàm lambda để bạn có thể làm điều gì đó như thế này:

012.
for i in seq(1, 9, lambda x: x*2): 
    print i 
... 
1 
2 
4 
8 

đâu seq được định nghĩa dưới đây:

#!/bin/python 
from timeit import timeit 

def seq(a, b, f): 
    x = a; 
    while x < b: 
     yield x 
     x = f(x) 

def testSeq(): 
    l = tuple(seq(1, 100000000, lambda x: x*2)) 
    #print l 

def testGen(): 
    l = tuple((2**x for x in range(27))) 
    #print l 

testSeq(); 
testGen(); 

print "seq", timeit('testSeq()', 'from __main__ import testSeq', number = 1000000) 
print "gen", timeit('testGen()', 'from __main__ import testGen', number = 1000000) 

Sự khác biệt về hiệu suất không phải là nhiều:

seq 7.98655080795 
gen 6.19856786728 

[EDIT]

Để hỗ trợ lặp đảo ngược và với đối số mặc định ...

def seq(a, b, f = None): 
    x = a; 
    if b > a: 
     if f == None: 
      f = lambda x: x+1 
     while x < b: 
      yield x 
      x = f(x) 
    else: 
     if f == None: 
      f = lambda x: x-1 
     while x > b: 
      yield x 
      x = f(x) 

for i in seq(8, 0, lambda x: x/2): 
    print i 

Lưu ý: Đây thường chạy khác để range/xrange trong đó sự chỉ đạo kiểm tra </> được lựa chọn bởi các dấu hiệu iterator, chứ không phải là sự khác biệt giữa đầu và cuối các giá trị.

Các vấn đề liên quan