2009-05-14 22 views
11

Trong một answer (bởi S.Lott) cho một câu hỏi về try...else tuyên bố của Python:"khác" được coi là có hại trong Python?

Trên thực tế, ngay cả trên một-tuyên bố nếu các khác: có thể bị lạm dụng trong thực sự khủng khiếp cách tạo lỗi mà rất khó để tìm. [...]

suy nghĩ hai lần về khác :. đó là nói chung là một vấn đề. Tránh nó trừ trong một if-tuyên bố và thậm chí sau đó xem xét tài liệu về điều kiện else- để làm nó rõ ràng.

Đây có phải là ý kiến ​​được tổ chức rộng rãi không? Có phải elseconsidered harmful?

Tất nhiên bạn có thể viết mã khó hiểu với nó nhưng điều đó đúng với bất kỳ cấu trúc ngôn ngữ nào khác. Ngay cả của Python for...else dường như với tôi một điều rất tiện dụng để có (ít hơn cho try...else).

+0

Xin chào dF. Trong một vùng nguy hiểm tương tự: a = b = c = 2 –

+1

Còn về vòng lặp, chúng có thể chạy mãi mãi khi bạn không muốn chúng. Có vẻ hơi quá tải nếu bạn loại bỏ các tính năng ngôn ngữ có khả năng gây nguy hiểm. – Milhous

Trả lời

30

S.Lott rõ ràng đã thấy một số mã không đúng ở đó. Không phải tất cả chúng ta? Tôi không xem xét khác có hại, mặc dù tôi đã nhìn thấy nó được sử dụng để viết mã xấu. Trong những trường hợp đó, tất cả các mã xung quanh cũng đã xấu, vậy tại sao đổ lỗi cho người nghèo khác?

+7

Đồng ý - quá dễ dàng để đổ lỗi cho các công cụ và không phải là người sử dụng chúng –

15

Không có gì không có hại, điều đó là cần thiết.

Luôn luôn có một tuyên bố tất cả. Tất cả các nút chuyển phải có mặc định. Tất cả đối sánh mẫu trong ngôn ngữ ML phải có mặc định.

Lý lẽ không thể lý giải điều gì là đúng sau một loạt các câu lệnh if là một thực tế của cuộc sống. Máy tính là máy trạng thái hữu hạn lớn nhất hiện có, và nó là ngớ ngẩn để liệt kê mọi khả năng duy nhất trong mọi tình huống.

Nếu bạn thực sự sợ rằng các lỗi không xác định không được chú ý trong các câu lệnh khác, có thật là khó có thể đưa ra một ngoại lệ ở đó không?

+3

Không đồng ý. Nên * không bao giờ * là một NẾU tất cả các bạn không thể thực sự nói lên logic dẫn đến catchall. Nếu bạn không thể xác định chính xác điều kiện nào dẫn đến catch-all, bạn có lỗi. –

+13

@ S.Lott vì vậy thay vì bắt các điều kiện không xác định trong câu lệnh khác, bạn sẽ để nó rơi qua và thực hiện bất kỳ mã nào còn lại trong hàm? – Unknown

+1

Cá nhân, tôi sẽ cấu trúc lại mã cho đến khi nó không còn đường dẫn mã, trong đó lập trình viên về cơ bản nói "Tôi không biết làm thế nào tôi có ở đây, nhưng tôi sẽ làm điều gì đó. Nó có thể sẽ hoạt động". Cho dù đó là "cái gì" là để nâng cao ProgrammerNotSmartEnoughException, hoặc để thực hiện phần còn lại của chương trình, bạn có một vấn đề. Có lẽ một vấn đề nhỏ hơn trong trường hợp ngoại lệ, nhưng vẫn là một vấn đề. –

6

Với tôi, toàn bộ khái niệm về các cấu trúc ngôn ngữ phổ biến nhất định vốn đã trở nên tồi tệ chỉ đơn giản là sai. Ngay cả goto cũng có vị trí của nó. Tôi đã nhìn thấy rất dễ đọc, có thể bảo trì mã bởi những người như Walter Bright và Linus Torvalds sử dụng nó. Tốt hơn hết là chỉ dạy cho các lập trình viên khả năng đọc và sử dụng thông thường hơn là tự ý khai báo các cấu trúc nhất định "có hại".

+2

Và tôi nghĩ gọi điện thoại khác "có hại" đang diễn ra quá xa. Tôi chỉ nói để suy nghĩ và làm cho điều kiện rõ ràng. Tôi không nói "không bao giờ sử dụng nó". –

7

Nói rằng điều khác được coi là có hại giống như nói rằng các biến hoặc lớp học có hại. Heck, nó thậm chí giống như nói rằng goto là có hại. Chắc chắn, mọi thứ có thể bị lạm dụng. Nhưng tại một số điểm, bạn chỉ cần tin tưởng các lập trình viên là người lớn và đủ thông minh để không làm được. Nếu bạn sẵn sàng không sử dụng một cái gì đó bởi vì một câu trả lời trên SO hoặc một bài đăng trên blog hoặc thậm chí là một bài báo nổi tiếng của Dijkstra đã nói với bạn rằng, bạn cần phải cân nhắc xem lập trình có phải là đúng nghề cho bạn.

+0

+1: vâng, ngay cả goto vẫn có một vị trí. Khi "GOTO được coi là có hại" được viết thì cần phải có sự giúp đỡ, nhưng có vẻ như các bài học đã được học. – dwc

+1

Không: người khác không có cùng mức độ tổn hại. Khác là cố ý mơ hồ. Nó có thể là một cách cẩu thả để nói "Tôi không thể giải thích được điều kiện, vì vậy tôi chỉ hy vọng rằng những người thích hợp sẽ rơi vào tình trạng khác của tôi". Nếu bạn đang làm điều đó loại không cẩu thả không suy nghĩ, bạn đang viết lỗi cố ý. –

+4

@ S.Lott - Tôi nghĩ rằng bạn đang bỏ lỡ quan điểm của tôi. Quan điểm của tôi là mọi người cần phải thoát khỏi "x là xấu, không sử dụng nó" tâm lý. ĐẶC BIỆT về mặt cấu trúc ngôn ngữ. –

7

Tôi sẽ không nói điều đó có hại, nhưng có những lúc tuyên bố khác có thể khiến bạn gặp rắc rối. Ví dụ, nếu bạn cần thực hiện một số xử lý dựa trên giá trị đầu vào và chỉ có hai giá trị đầu vào hợp lệ. Chỉ kiểm tra xem ai có thể giới thiệu một lỗi. ví dụ:

The only valid inputs are 1 and 2: 

if(input == 1) 
{ 
    //do processing 
    ... 
} 
else 
{ 
    //do processing 
    ... 
} 

Trong trường hợp này, bằng cách sử dụng khác sẽ cho phép tất cả các giá trị khác hơn 1 để được xử lý khi nó chỉ nên được cho các giá trị 1 và 2.

+3

trong trường hợp này bạn nên làm khác nếu (input == 2) và sau đó có một {throw InvalidInput} khác – Unknown

+0

chính xác. Tôi đã từng bị lỗi này nhiều lần khi cố gắng bảo trì trên các ứng dụng cũ. Tôi cố gắng sử dụng khác chỉ đơn giản là để ném ngoại lệ cho dữ liệu không hợp lệ, đó là trừ khi tất cả tôi cần là một tuyên bố nếu đơn. –

+0

nan, tôi sẽ chỉ có nếu (input == 2) và không có gì khác, vì vậy không có gì sẽ xảy ra nếu đầu vào không phải là 1 hoặc 2 ... ví dụ tốt như vậy +1 – TStamper

0

Trong ví dụ này thừa nhận của bị khó lý do, nó có thể được viết một cách rõ ràng, nhưng người khác vẫn còn cần thiết. Ví dụ:

if a < 10:  
    # condition stated explicitly 
elif a > 10 and b < 10:  
    # condition confusing but at least explicit 
else:  
    # Exactly what is true here?  
    # Can be hard to reason out what condition is true 

có thể được viết

if a < 10:  
    # condition stated explicitly 
elif a > 10 and b < 10:  
    # condition confusing but at least explicit 
elif a > 10 and b >=10: 
    # else condition 
else: 
    # Handle edge case with error? 
+0

-1: Phiên bản thứ hai không rõ ràng hơn phiên bản đầu tiên. Nếu không có knwoing lý do cho mã, hoặc là có thể hợp lệ. –

+1

Nó làm cho tất cả các tùy chọn rõ ràng, mệnh đề khác sẽ chỉ được gọi khi có lỗi trong logic của ba tùy chọn đầu tiên. vẫn là một ví dụ khá vô nghĩa chắc chắn. – Nat

+1

Hãy xem xét lập trình viên bảo trì, những người thay đổi một số mệnh đề nhưng không nghĩ qua logic (tối nghĩa). Bây giờ "trường hợp cạnh" đột nhiên bắt đầu xảy ra vì những thay đổi mã kém chất lượng. Ném các cạnh trường hợp vào một người khác sẽ dẫn đến những bí ẩn. Xử lý lỗi không thể tưởng tượng (ví dụ 2) sẽ lộ ra lỗi bảo trì ngay lập tức. –

3

khác là hữu ích nhất khi ghi lại các giả định về mã. Nó đảm bảo rằng bạn đã suy nghĩ qua cả hai mặt của một câu lệnh if.

Luôn sử dụng mệnh đề khác với mỗi câu lệnh nếu thậm chí là thực tiễn được đề xuất trong "Hoàn thành mã".

+0

Vâng, tôi đã nghĩ đến câu nói đó trong Code Complete! Tôi cảm thấy một chút hư hỏng khi nhớ điều đó! –

2

Lý do đằng sau bao gồm tuyên bố else (trong số try...else) trong Python ở nơi đầu tiên là chỉ bắt các trường hợp ngoại lệ mà bạn thực sự muốn. Thông thường, khi bạn có một khối try...except, có một số mã có thể tăng ngoại lệ và sau đó có một số mã khác chỉ nên chạy nếu mã trước đó thành công. Nếu không có một khối else, bạn phải đặt tất cả các mã trong khối try:

try: 
    something_that_might_raise_error() 
    do_this_only_if_that_was_ok() 
except ValueError: 
    # whatever 

Vấn đề là, những gì nếu do_this_only_if_that_was_ok() đặt ra một ValueError? Nó sẽ bị phát hiện bởi tuyên bố except, khi bạn có thể không muốn nó. Đó là mục đích của khối else:

try: 
    something_that_might_raise_error() 
except ValueError: 
    # whatever 
else: 
    do_this_only_if_that_was_ok() 

Tôi đoán đó là một vấn đề quan điểm chừng mực nào đó, nhưng cá nhân tôi nghĩ rằng đây là một ý tưởng tuyệt vời, mặc dù tôi sử dụng nó rất hiếm. Khi tôi sử dụng nó, nó chỉ cảm thấy rất thích hợp (và bên cạnh đó, tôi nghĩ rằng nó giúp làm rõ các dòng mã một chút)

+0

Tôi không thể không cảm thấy rằng nếu bạn muốn 'do_this_only_if_that_was_ok' được gọi là một trong hai cách và bạn nghĩ rằng nó có thể gây ra lỗi giá trị, nó sẽ rõ ràng hơn để thêm nó vào một tuyên bố riêng biệt (giả sử bạn đang cố gắng tách chúng ra đó là). –

+0

Nhưng tôi không muốn nó được gọi là một trong hai cách (tức là cho dù ngoại lệ được nâng lên hay không), tôi muốn nó chỉ được gọi là nếu something_that_might_raise_error() đã không đưa ra một lỗi. Và nếu do_this_only_if_that_was_ok() gây ra lỗi, nó sẽ không bị bắt (ít nhất là không ở mức này). Tôi không thấy cách nào khác ngoài cách tôi viết ở đây. –

3

Au contraire ... Theo tôi, PHẢI là một người khác cho mỗi nếu. Cấp, bạn có thể làm những điều ngu ngốc, nhưng bạn có thể lạm dụng bất kỳ cấu trúc nào nếu bạn cố gắng hết sức. Bạn biết câu nói "một người lập trình thực sự có thể viết FORTRAN bằng mọi ngôn ngữ".

Điều tôi làm rất nhiều thời gian là viết phần khác làm nhận xét, mô tả lý do tại sao không có gì để làm.

1

Dường như với tôi, đối với bất kỳ ngôn ngữ nào và bất kỳ câu lệnh kiểm soát dòng chảy nào có kịch bản hoặc tác dụng phụ mặc định, kịch bản đó cần phải có cùng mức độ xem xét. Logic trong if hoặc switch hoặc while chỉ tốt như điều kiện if (x) while (x) hoặc for (...). Do đó tuyên bố không có hại nhưng logic trong tình trạng của chúng là.

Do đó, với tư cách là nhà phát triển, chúng tôi có trách nhiệm viết mã với phạm vi rộng của người khác trong tâm trí. Quá nhiều nhà phát triển coi nó như là một 'nếu không phải là ở trên' khi thực tế nó có thể bỏ qua tất cả các cảm giác thông thường bởi vì logic duy nhất trong nó là sự phủ định của logic trước đó, thường không đầy đủ. (bản thân lỗi thiết kế thuật toán)

Tôi không xem xét 'khác' bất kỳ điều gì có hại hơn các công cụ off-by-in trong vòng lặp for() hoặc quản lý bộ nhớ kém. Đó là tất cả về các thuật toán. Nếu automata của bạn đã hoàn thành trong phạm vi của nó và các nhánh có thể, và tất cả đều cụ thể và được hiểu thì không có nguy hiểm.Sự nguy hiểm là lạm dụng logic đằng sau các biểu thức của những người không nhận ra tác động của logic phạm vi rộng. Máy tính ngu ngốc, họ làm những gì họ đang nói với nhà điều hành của họ (về mặt lý thuyết)

tôi làm xét thửbắt là nguy hiểm vì nó có thể phủ nhận xử lý một số lượng không rõ mã. Chi nhánh phía trên nâng cao có thể chứa lỗi, được đánh dấu bằng cách tự động nâng cao. Điều này có thể không rõ ràng. Nó giống như việc chuyển một tập hợp các chỉ lệnh tuần tự thành một cây hoặc đồ thị xử lý lỗi, trong đó mỗi thành phần phụ thuộc vào các nhánh trong phần tử cha. Odd. Tâm trí bạn, tôi yêu C.

0

Tôi nghĩ điểm liên quan đến try...except...else là việc sử dụng nó là một sai lầm dễ dàng để tạo trạng thái không nhất quán thay vì sửa lỗi. Nó không phải là nó nên tránh bằng mọi giá, nhưng nó có thể phản tác dụng.

xem xét:

try: 
    file = open('somefile','r') 
except IOError: 
    logger.error("File not found!") 
else: 
    # Some file operations 
    file.close() 
# Some code that no longer explicitly references 'file' 

Sẽ thật tốt đẹp để nói rằng khối trên ngăn chặn mã từ cố gắng để truy cập vào một tập tin đó không tồn tại, hoặc một thư mục mà người dùng không có quyền truy cập, và để nói rằng mọi thứ được đóng gói bởi vì nó nằm trong khối try...except...else. Nhưng trong thực tế, rất nhiều mã trong các hình thức nêu trên thực sự nên xem xét như thế này:

try: 
    file = open('somefile','r') 
except IOError: 
    logger.error("File not found!") 
    return False 
# Some file operations 
file.close() 
# Some code that no longer explicitly references 'file' 

Bạn thường lừa mình bằng cách nói rằng vì file không còn được nhắc đến trong phạm vi, nó không quan trọng để đi vào mã sau khối, nhưng trong nhiều trường hợp một cái gì đó sẽ đến nơi mà nó chỉ là không ổn. Hoặc có thể một biến sau đó sẽ được tạo trong khối else không được tạo trong khối except.

Đây là cách tôi sẽ phân biệt if...else từ try...except...else. Trong cả hai trường hợp, người ta phải làm cho các khối song song trong hầu hết các trường hợp (các biến và trạng thái được đặt trong một nên được đặt ở vị trí khác) nhưng ở phần sau, các lập trình viên thường không, có khả năng là không thể hoặc không liên quan. Trong những trường hợp như vậy, nó thường sẽ làm cho toàn bộ ý nghĩa hơn nhiều để trở về người gọi hơn là cố gắng và tiếp tục làm việc xung quanh những gì bạn nghĩ rằng bạn sẽ có trong kịch bản trường hợp tốt nhất.

4

Nếu bạn viết:

if foo: 
    # ... 
elif bar: 
    # ... 
# ... 

sau đó người đọc có thể để tự hỏi: điều gì nếu không phải foo cũng không bar là đúng? Có lẽ bạn biết, từ sự hiểu biết của bạn về mã, rằng nó phải là trường hợp mà foo hoặc bar. Tôi muốn xem:

if foo: 
    # ... 
else: 
    # at this point, we know that bar is true. 
    # ... 
# ... 

hay:

if foo: 
    # ... 
else: 
    assert bar 
    # ... 
# ... 

này làm cho nó rõ ràng đối với người đọc như thế nào bạn mong đợi kiểm soát chảy, mà không đòi hỏi người đọc phải có kiến ​​thức thân mật của nơi foobar đến từ.

(trong trường hợp ban đầu, bạn vẫn có thể viết nhận xét giải thích những gì đang xảy ra, nhưng tôi nghĩ tôi sẽ tự hỏi: "Tại sao không chỉ sử dụng mệnh đề else:?")

Tôi nghĩ rằng điểm không phải là bạn không nên sử dụng else:; đúng hơn, đó một khoản else: thể cho phép bạn viết không rõ ràng đang và bạn nên cố gắng nhận ra khi điều này xảy ra và thêm một nhận xét nhỏ để giúp đỡ bất kỳ độc giả

đó là sự thật về hầu hết mọi thứ trong ngôn ngữ lập trình, thực sự :-)

+2

+1: nếu foo: something; else: khẳng định thanh; thứ gì khác. Làm cho nó rõ ràng theo một cách nào đó. –

1

có một cái gọi là "treo lủng lẳng khác" vấn đề đó là gặp phải trong các ngôn ngữ gia đình C như sau:.

if (a==4) 
if (b==2) 
printf("here!"); 
else 
printf("which one"); 

đang vô tội này có thể được hiểu theo hai cách:

if (a==4) 
    if (b==2) 
     printf("here!"); 
    else 
     printf("which one"); 

hoặc

if (a==4) 
    if (b==2) 
     printf("here!"); 
else 
    printf("which one"); 

Vấn đề là các "khác" được "treo lủng lẳng", người ta có thể nhầm lẫn giữa chủ sở hữu của người khác. Tất nhiên trình biên dịch sẽ không làm cho sự nhầm lẫn này, nhưng nó là hợp lệ cho người chết.

Nhờ Python, chúng ta không thể có một vấn đề khác treo lủng lẳng bằng Python vì chúng ta phải viết một trong hai

if a==4: 
    if b==2: 
     print "here!" 
else: 
    print "which one" 

hoặc

if a==4: 
    if b==2: 
     print "here!" 
    else: 
     print "which one" 

Vì vậy mà mắt người bắt nó. Và, không, tôi không nghĩ "khác" là có hại, nó có hại như "nếu".

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