2016-11-14 20 views
5

Python cho phép một "if" tình trạng comprehensions danh sách, ví dụ:điều kiện Compound trong một vòng lặp for

[l for l in lines if l.startswith('example')] 

Tính năng này là mất tích trong thường xuyên "for" vòng lặp, như vậy trong sự vắng mặt của:

for line in lines if line.startswith('example'): 
    statements 

cần đánh giá điều kiện trong vòng lặp:

for line in lines: 
    if line.startswith('example'): 
     statements 

hoặc để nhúng biểu thức trình tạo, như:

for line in [l for l in lines if l.startswith('example')]: 
    statements 

Hiểu biết của tôi có chính xác không? Có một cách tốt hơn hoặc nhiều hơn pythonic hơn những người tôi liệt kê ở trên để đạt được kết quả tương tự của việc thêm một điều kiện trong vòng lặp for?

Hãy lưu ý rằng "dòng" đã được chọn làm ví dụ, bất kỳ bộ sưu tập hoặc trình tạo nào cũng có thể ở đó.

+0

Bạn hỏi làm thế nào để có được điều kiện hợp chất trong một vòng lặp for ? –

+3

Nhưng chúng giống hệt nhau. Bạn đọc danh sách hiểu từ trái sang phải, và nó chứa các chức năng chính xác giống như đầy đủ cho vòng lặp. –

+0

Bạn có thể nói chính xác câu hỏi của bạn là gì không? –

Trả lời

2

Một số ý tưởng hay xuất phát từ các câu trả lời và nhận xét khác, nhưng tôi nghĩ this recent discussion on Python-ideasits continuation là câu trả lời hay nhất cho câu hỏi này.

Để tóm tắt: các ý tưởng đã được thảo luận trong quá khứ, và những lợi ích dường như không đủ để thúc đẩy sự thay đổi cú pháp, xem xét:

  • tăng độ phức tạp về ngôn ngữ và tác động đối với đường cong học tập

  • các thay đổi kỹ thuật trong tất cả các triển khai: CPython, Jython, Pypy ..

  • các tình huống lạ có thể xảy ra khi sử dụng triệt để tổng hợp có thể dẫn đến

Một điểm mà mọi người dường như đánh giá cao là tránh mang đến sự phức tạp giống như Perl làm tổn hại đến khả năng bảo trì.

This messagethis one độc đáo tóm tắt giải pháp thay thế tốt (gần như đã xuất hiện trong trang này cũng) để một hợp chất if-tuyên bố trong cho vòng lặp:

# nested if 
for l in lines: 
    if l.startswith('example'): 
     body 

# continue, to put an accent on exceptional case 
for l in lines: 
    if not l.startswith('example'): 
     continue 
    body 

# hacky way of generator expression 
# (better than comprehension as does not store a list) 
for l in (l for l in lines if l.startswith('example')): 
    body() 

# and its named version 
def gen(lines): 
    return (l for l in lines if l.startswith('example')) 
for line in gen(lines): 
    body 

# functional style 
for line in filter(lambda l: l.startswith('example'), lines): 
    body() 
+1

'bộ lọc' phải là cách khác xung quanh:' bộ lọc (lambda l: l.startswith ('example'), dòng) ' –

+0

@tobias_k done, thanks! – Pintun

1

Có thể không phải Pythonic, nhưng bạn có thể filter các dòng.

for line in filter(lambda l: l.startswith('example'), lines): 
    print(line) 

Và bạn có thể xác định chức năng lọc của riêng mình, tất nhiên, nếu lambda đó làm phiền bạn hoặc bạn muốn lọc phức tạp hơn.

def my_filter(line): 
    return line.startswith('example') or line.startswith('sample') 

for line in filter(my_filter, lines): 
    print(line) 

Tôi muốn nói rằng điều kiện trong vòng lặp tốt hơn vì bạn không duy trì danh sách "được lọc" trong bộ nhớ khi bạn lặp qua các dòng.

Vì vậy, mà chỉ muốn được

for line in file: 
    if not my_filter(line): 
     continue 
    # statements 
+0

Đẹp nhất, cảm ơn. Tôi đã nghĩ về điều đó nhưng quên thêm nó. Mặc dù, tôi vẫn nghĩ rằng nó không có khả năng đọc của chỉ có một điều kiện trong vòng lặp chính nó. Tôi tự hỏi nếu tôi là người đầu tiên cảm thấy cần cú pháp như vậy. – Pintun

+1

@Pintun FWIW, điều này vừa được thảo luận cách đây không lâu về các ý tưởng Python, nơi bạn có thể đọc câu trả lời của một số nhà phát triển CPython cốt lõi: [September 2016] (https://mail.python.org/pipermail/python -ideas/2016-September/042270.html) và tiếp tục vào [Tháng 10 năm 2016] (https://mail.python.org/pipermail/python-ideas/2016-October/042640.html). Từ những gì tôi thu thập, ý tưởng này cũng đã xuất hiện một vài lần trước đó. Tôi mạnh mẽ khuyến khích bạn đọc toàn bộ chuỗi. –

+0

@suspicousdog cảm ơn, tôi đã tìm thấy mọi thứ tôi đang tìm kiếm: một tham chiếu đến một cuộc thảo luận trước đó, lý do kỹ thuật và thẩm mỹ có lợi và chống lại thay đổi, ví dụ tuyệt vời về các lựa chọn thay thế. Tôi thấy đặc biệt thú vị [this] (https://mail.python.org/pipermail/python-ideas/2016-September/042273.html) tin nhắn, rằng tôi sẽ sử dụng như là một hướng dẫn cho một câu trả lời tự. Tôi không biết [Python-ideas] (https://mail.python.org/mailman/listinfo/python-ideas), liên kết tuyệt vời! – Pintun

0

của nó không phải là tính năng còn thiếu, tôi không thể nghĩ ra cách nào nó có thể được thực hiện ngoại trừ trong một số trường hợp đặc biệt. (l for l in lines if l.startswith('example')) là một đối tượng máy phát điện và biến số l là cục bộ cho đối tượng đó. Các for chỉ nhìn thấy những gì đã được trả về bởi phương pháp __next__ của máy phát điện.

for là rất khác nhau vì kết quả của trình tạo cần phải được ràng buộc với một biến trong phạm vi của người gọi. Bạn có thể đã viết

for line in (line for line in lines if l.startswith('example')): 
    foo(line) 

một cách an toàn vì hai số này nằm trong các phạm vi khác nhau.

Hơn nữa, trình tạo không chỉ phải trả về biến cục bộ của nó. Nó có thể đánh giá bất kỳ biểu thức nào. Làm thế nào bạn sẽ tắt này?

for line in (foo(line)+'bar' for line in lines if line.startswith('example')): 
    statements 

Giả sử bạn có một danh sách liệt kê

for l in (l[:] for l in list_of_lists if l): 
    l.append('modified') 

Đó không nên gắn liền với các danh sách ban đầu.

0

Có cách nào tốt hơn hay nhiều hơn so với những gì tôi đã liệt kê ở trên để đạt được cùng một kết quả của việc thêm điều kiện vào vòng lặp for?

Không, không có, và không nên có; đó là lý do cho lý do tại sao danh sách hiểu được ở đây ở nơi đầu tiên. Từ corresponding PEP:

Danh sách

comprehensions cung cấp một cách ngắn gọn hơn để tạo các danh sách trong tình huống mà map()filter() và/hoặc lồng vòng sẽ hiện được sử dụng.

Đọc danh sách cấu thành thay thế cho lồng nhau for, if s; tại sao bạn lại muốn một giải pháp thay thế?

Nếu bạn cần sử dụng if với for, bạn lồng vào bên trong nó, nếu bạn không muốn làm điều đó, bạn sử dụng danh sách hiểu. Phẳng tốt hơn so với lồng nhaunhưngsố khả năng đọc; cho phép một số if sẽ dẫn đến các dòng dài xấu khó phân tích bằng mắt thường hơn.

+0

"Danh sách hiểu được cấu thành một sự thay thế cho lồng nhau cho, nếu, tại sao bạn sẽ muốn một thay thế cho thay thế?" Họ không phải là một thay thế trong trường hợp này: một danh sách hiểu vẫn cần một vòng lặp for để được lặp lại. – Pintun

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