2012-07-07 35 views
9

Tôi không có ý định lãng phí thời gian của bạn, nhưng: đã xảy ra với bạn quá, trong khi sử dụng câu lệnh with của Python rằng nó thực sự trái với dòng thứ 5 của "The Zen của Python "mà đi" Phẳng là tốt hơn so với lồng nhau "? Có thể bất kỳ guru Python giác ngộ chia sẻ cho tôi một số hiểu biết của họ về điều này?zen của Python vs với tuyên bố - suy luận triết học

(Tôi luôn luôn thấy rằng thêm một mức độ indentation bật lên trong mã của tôi mỗi khi tôi sử dụng with thay vì f.close() ... và nó không thích Tôi sẽ không sử dụng try: ... finally: ... anyways và do đó những lợi ích của with vẫn trốn tránh tôi, ngay cả khi tôi lớn để thích và hiểu Python ngày càng nhiều ...)


@glglgl (xin lỗi, tôi không thể tìm thấy một cách để viết mã trong ý kiến): có, nhưng nếu bạn hãy đi theo cách with, mã của bạn sẽ trở thành:

try: 
    with file(...) as f: 
     ... 
except IOError: 
    ... 

... và chỉ sử dụng mà không có try là những gì mọi người sẽ làm trong loại mã "một lần sử dụng" hacky mà họ sử dụng f.close() thay vì bằng anyways (điều này không tốt vì tệp có thể không bị đóng nếu một ngoại lệ được ném trước f.close()), do đó, đối với những người "hacky" chỉ không sử dụng with bởi vì, tôi không biết, tôi đoán họ chỉ tìm thấy nó quá "ưa thích" và cho mã có cấu trúc tốt mà nó không mang lại bất kỳ lợi ích anyways, vì vậy có vẻ như với tôi không có trường hợp sử dụng thực tế còn lại cho nó ... đó là suy nghĩ của tôi về thực sự.

+1

Hầu hết thời gian tôi chỉ cho phép IOError truyền và bắt nó ở một nơi khác. – Dikei

+0

Nhiều như tôi không đồng ý với tiền đề của câu hỏi này, tôi phải cung cấp cho bạn các đạo cụ để làm cho tôi quay trở lại và đọc lại PEP [342] (http: //www.python.org/dev/peps/pep-0342 /) và [343] (http://www.python.org/dev/peps/pep-0343/) – kojiro

Trả lời

5

Có, The Zen of Python nói "Phẳng tốt hơn lồng nhau", tuy nhiên nó không phải là đặc điểm duy nhất mà chúng tôi quan tâm; nó cũng nói "Đơn giản là tốt hơn so với phức tạp". Vẻ đẹp của with là nó thực sự tuân thủ cả hai nguyên tắc như tôi sẽ giải thích bên dưới.

Bất cứ khi nào bạn thấy mình đang suy nghĩ về triết lý về một tính năng bằng Python, có lẽ bạn nên tìm hiểu về động lực đằng sau đối tượng địa lý. Trong trường hợp này PEP 343 -- The "with" Statement nói nó lên phía trước một cách trừu tượng:

PEP này thêm một tuyên bố mới "với" với ngôn ngữ Python để làm cho nó thể yếu tố ra sử dụng tiêu chuẩn của try/cuối cùng báo cáo.

Việc tính toán mã đơn giản và dễ đọc hơn. Tuy nhiên,

PEP 343 đi sâu hơn việc cung cấp một số đường cú pháp đơn giản. Nó thiết lập một giao thức quản lý bối cảnh:

Khái niệm ngay sau với từ khóa vào báo cáo kết là một "biểu hiện bối cảnh" như biểu hiện cung cấp các đầu mối chính như đối với môi trường runtime người quản lý bối cảnh thiết lập cho thời hạn của phần tử tuyên bố.

Sử dụng giao thức người quản lý ngữ cảnh, người viết API có thể giúp che giấu sự phức tạp và đảm bảo thu thập/giải phóng tài nguyên chính xác trong ngữ cảnh đa luồng.

Nhưng vẻ đẹp thực sự của tuyên bố with được hiển thị trong Ví dụ 12 PEP 343 mà giải thích rằng:

A "lồng" quản lý bối cảnh đó tự động làm tổ được cung cấp bối cảnh từ trái sang phải để tránh thụt lề quá mức.

Sử dụng quản lý nested() bối cảnh mà bạn có thể lấy mã trông như thế này:

with a as x: 
    with b as y: 
     with c as z: 
      # Perform operation 

và biến nó thành này:

with nested(a, b, c) as (x, y, z): 
      # Perform operation 

Lưu ý rằng nested() đã được giới thiệu trong Python 2.5, nhưng kể từ phiên bản 2.7, nó không còn được dùng để ủng hộ dạng cú pháp quản lý ngữ cảnh đa ngữ này:

with a as x, b as y, c as z: 
      # Perform operation 

Rõ ràng không chỉ đơn giản và dễ đọc hơn mà còn phẳng hơn nhiều so với lồng nhau. Vì vậy, sử dụng with là đi theo con đường của 無爲 :)

UPDATE: Để đối phó với comments on Simeon Visser's answer đây là một ví dụ khi bạn có thể sử dụng nhiều nhà quản lý bối cảnh để mở nhiều hơn một tập tin cùng một lúc, khi bạn muốn nén các nội dung của hai (hay nhiều) tập tin với nhau như vậy mà nếu mở một trong các tập tin không nó sẽ làm cho toàn bộ điều thất bại và đóng đúng cách mỗi tập tin đã được mở:

from itertools import izip 
with open("/etc/passwd") as a, open("/etc/group") as b, open("/etc/shadow") as c: 
    for lines in izip(a,b,c): 
     print map(lambda x: x.split(':')[0], lines) 

Run ví dụ này hai lần; một lần như là một gốc và một lần như người dùng bình thường. Giả sử bạn lưu tệp này là ziptogether.py trước tiên hãy thử gọi nó là gốc với sudo python ziptogether.py và nó sẽ thành công, nhưng gọi nó là người dùng bình thường với python ziptogether.py sẽ thất bại vì bạn không có quyền đọc /etc/shadow. Khi trình quản lý ngữ cảnh thất bại sẽ đảm bảo rằng các tệp đã được mở thành công trước khi lỗi được đóng đúng cách khi thực thi di chuyển ra ngoài phạm vi của câu lệnh with.

+1

kudo. câu trả lời đẹp và nhiều thông tin! – NeuronQ

+1

@NeuronQ Tôi đã cập nhật câu trả lời của mình để lưu ý rằng 'nested()' không được chấp nhận và có một dạng cú pháp đơn giản hơn cho nhiều trình quản lý ngữ cảnh. – aculich

7

Bạn đề cập đến nó đã: Đó là sạch hơn để làm

f = file(...) 
try: 
    # do work on file 
finally: 
    f.close() 

hơn là chỉ đóng cửa sau khi các hoạt động tập tin - đó sẽ không thể đạt được nếu một ngoại lệ xảy ra.

Nếu bạn so sánh try/finally với with, bạn có cùng mức thụt lề, vì vậy bạn không mất bất kỳ thứ gì. Tuy nhiên, nếu bạn xử lý ngoại lệ, bạn có thêm một mức thụt đầu dòng, điều này thực sự chống lại điểm Zen đã nói.

OTOH, with đóng gói mọi thứ và làm cho việc sử dụng chúng dễ dàng hơn và dễ đọc hơn, đó là các khía cạnh Zen khác.

Dường như tôi không thể theo dõi mọi khía cạnh Thiền một cách chính xác; đôi khi bạn phải cân nhắc cái này với cái kia. Trong trường hợp này, bạn "mất" một mức thụt đầu dòng, nhưng bạn sẽ có được khả năng đọc và bảo trì tốt hơn. Sau này có vẻ là một lợi thế cho tôi.

+0

Tôi đã cố trả lời bạn nhưng không thể tìm ra cách viết mã trong các ý kiến ​​vì vậy tôi đã thêm câu trả lời của tôi cho bạn vào cuối câu hỏi của tôi – NeuronQ

+0

@NeuronQ Tôi đã cập nhật câu trả lời – glglgl

+0

Tôi đồng ý: Các yếu tố của Zen of Python thường cần phải được giao dịch với nhau. Trong trường hợp hiện tại, tôi cho rằng mức độ làm tổ mà bạn phải đầu tư cho phép bạn theo dõi ** Rõ ràng là tốt hơn là ngầm **: Khi bạn thấy một 'với', rõ ràng việc xử lý kết thúc sẽ xảy ra (thay vì tùy thuộc vào số phận thực hiện của logic). "Rõ ràng là tốt hơn là tiềm ẩn" là số 2 trên danh sách Zen của Python và vì vậy * nên * thường xuyên ít làm tổ hơn. Tất cả đều tốt. –

7

Lưu ý rằng Zen của Python cũng nói:

Đơn giản là tốt hơn so với phức tạp.

Phức hợp phức tạp hơn là phức tạp.

Độ khó tính.

Sử dụng một trình quản lý nội dung trong báo cáo with cung cấp nhiều điều:

  • hành vi đúng như các tập tin luôn đóng
  • dễ đọc (with open(..) as f là khá dễ hiểu)

Bạn có thể 't chỉ vào một mục trong Zen của Python và cho rằng tất cả mã Python phải đáp ứng tất cả các mục mọi lúc. Ví dụ, nếu mức thụt lề tối thiểu để giải quyết một vấn đề cụ thể theo một cách dễ đọc và chính xác là bốn, thì cũng vậy: nếu mức thụt lề của ba làm cho mã ít có thể đọc được thì chỉ cần để mã một mình (bốn là tốt).

+0

Những gì bạn nói là rất, rất chung ... Bạn đang ở trên "thực thi đúng hành vi" điểm, vì điều này sẽ là tốt cho mã hacky nhanh chóng, nhưng tôi thấy rằng chính xác những người viết "mã hack nhanh" don không sử dụng câu lệnh. Và phần dễ đọc là chủ quan (tôi tìm thấy một mức thụt đầu dòng ít đọc được hơn, và khi bạn làm một "nhiều tệp với" như "với mở (...) dưới dạng tệp1, mở (...) dưới dạng tệp3, mở (. ..) như file4: "nó kết thúc lên rất khó đọc vì bạn phải di chuyển theo chiều ngang hoặc xấu xí bởi vì bạn chia với tuyên bố trên nhiều dòng. – NeuronQ

+0

Có một lý do tốt cho bốn tập tin được mở cùng một lúc? Thông thường tôi có thể đọc dữ liệu từ các tập tin đầu vào tuần tự và tương tự để ghi dữ liệu vào một hoặc nhiều tập tin đầu ra Mặc dù tôi có thể tưởng tượng rằng có những tình huống cần bốn tập tin. –

+0

@NeuronQ: Tôi không thể nhìn thấy gì ngoài việc ngắt lệnh nhiều dòng hơn, đặc biệt khi các phần 'mở (...) như fX' được căn chỉnh. Tôi đồng ý với Simeon nó không phải là trường hợp điển hình. Dù sao, nó có thể đọc được giống như khi bốn kết quả' fX = mở (. ..) 'lệnh được sử dụng. – pepr

1
"Flat is better than nested" 

Vâng, phẳng là gì?

import thirdparty 
print "I Like Pie!" 

vs

import org.example.thirdparty.something 
System.out.println("I Like Cake") 

vv ...

The Zen của Python không chỉ đơn giản là thực thi một giới hạn thụt đầu dòng trên mã của bạn. Nó khuyến khích bạn viết mã có thể đọc được (và do đó, tốt hơn). Nếu câu lệnh with của bạn nằm trong một chức năng chỉ có thể truy cập được bởi 3 lớp đối tượng (vd: one.two.three.func()), thì đó là một vấn đề.

Nếu không, ba mức lưu ý chỉ là một con số tốt như bất kỳ.

1

Lý do để thích with là bạn không cần phải ghép tay các hoạt động liên quan (như open(...)/.close(); nhưng with xây dựng là tổng quát hơn - không chỉ để làm việc với các tập tin). Điều này quan trọng là trong trường hợp khi thao tác thứ hai có thể không được thực thi vì các lý do không hiển thị rõ ràng từ mã nguồn. Bạn đang nói với máy chăm sóc nó cho tôi, và máy tốt hơn trong trường hợp hơn con người. Bằng cách này, bạn thoát khỏi nhóm các lỗi khó chịu có thể khó tìm.

Nhân tiện, bạn nên sử dụng open(...) thay vì file(...). Python 3 không biết gì về file(...) và nếu không bạn sẽ phải sửa mã của mình sau.

+0

Thật vậy, có lẽ tôi nên khám phá việc sử dụng 'with' với những thứ khác ngoài tập tin, tôi chưa bao giờ thực sự đưa ra một suy nghĩ tốt. Yeah, 'open (...) 'là cái tôi dùng, tôi không biết tâm trí của mình là khi nào tôi viết' file (...) 'nhưng may mắn thay nó không ảnh hưởng đến ý nghĩa của câu hỏi. – NeuronQ