2010-09-29 31 views
8

Phương pháp này tìm kiếm nhóm ký tự đầu tiên (ví dụ: [a-zA-Z0-9_]), trả về nhóm phù hợp đầu tiên hoặc None trong trường hợp thất bại.Hoạt động "Boolean" trong Python (ví dụ: và/hoặc toán tử)

def test(str): 
    m = re.search(r'(\w+)', str) 
    if m: 
     return m.group(1) 
    return None 

Chức năng tương tự có thể được viết lại như sau:

def test2(str): 
    m = re.search(r'(\w+)', str) 
    return m and m.group(1) 

này hoạt động giống nhau, và được ghi chép lại hành vi; như this page ghi rõ:

Biểu thức x and y đánh giá đầu tiên x; nếu x là sai, giá trị của nó được trả về; nếu không, y được đánh giá và giá trị kết quả được trả về.

Tuy nhiên, là một toán tử boolean (nó thậm chí còn nói như vậy trên hướng dẫn), tôi mong đợi and để trả về boolean. Kết quả là, tôi là astonished khi tôi phát hiện ra (cách này) hoạt động như thế nào.

Các trường hợp sử dụng khác của vấn đề này là gì và/hoặc lý do cơ bản cho việc triển khai thay vì không trực quan này là gì?

+1

Trên thực tế có một vài ngôn ngữ có điều này, nó chắc chắn có trước Python. Nó được sử dụng theo truyền thống như là một thay thế cho điều kiện bậc ba, trở lại trước khi chúng ta có các biểu thức 'if ... else', và nó vẫn có thể được sử dụng như toán tử kết hợp null của C#' ?? '. Cá nhân tôi sẽ cố gắng tránh tất cả nhưng việc sử dụng tầm thường nhỏ này, cả vì những vấn đề tiềm ẩn với các giá trị ‘giả” và bởi vì “rõ ràng là tốt hơn là ngầm”. 'return m và m.group (1)' là khá nhiều OK, nhưng nếu bạn đi xa hơn thế, 'm không phải là None và ...' có thể rõ ràng hơn. – bobince

Trả lời

5

trường hợp sử dụng khác của việc này là gì,

conciseness (và do đó rõ ràng, ngay sau khi bạn làm quen với nó, kể từ sau khi tất cả nó không hy sinh khả năng đọc ở tất cả -!) bất kỳ lúc nào bạn cần kiểm tra điều gì đó và sử dụng điều gì đó nếu đó là sự thật hoặc giá trị khác nếu điều gì đó sai (đó là and - đảo ngược nó cho or - và tôi rất cố ý tránh từ khóa thực sự hoặc - giống như TrueFalse, vì tôi đang nói bout mỗi đối tượng, không chỉ bool! -).

Không gian dọc trên màn hình máy tính bị hạn chế, và được lựa chọn, nó được sử dụng tốt nhất để hỗ trợ khả năng đọc hữu ích (docstrings, comments, các dòng trống được đặt chiến lược để tách các khối, ...). ngành liên quan như:

inverses = [x and 1.0/x for x in values] 

thành sáu như:

inverses = [] 
for x in values: 
    if x: 
     inverses.append(1.0/x) 
    else: 
     inverses.append(x) 

hoặc chật chội hơn phiên bản đó.

và/hoặc lý do hợp lý cho việc thực hiện này là không thực tế hơn là gì?

Thay vì là "unintuitive", người mới bắt đầu thường xuyên bị vấp lên bởi thực tế là một số ngôn ngữ (như tiêu chuẩn Pascal) đã không định trình tự đánh giá và tính chất ngắn circuiting của andor; Một trong những điểm khác biệt giữa Turbo Pascal và chuẩn ngôn ngữ, trở lại trong ngày đã làm cho Turbo trở thành phương ngữ Pascal phổ biến nhất mọi thời đại, chính xác là Turbo đã thực hiện andor giống như Python đã làm sau đó (và ngôn ngữ C đã làm trước đó .. .).

+1

Không phải là nghĩa vụ phải là 'x và 1.0/x cho ...'? – NullUserException

+0

@Null, ** oops **, bạn nói đúng - hãy xem, bạn _do_ tìm thấy cấu trúc có thể đọc được mặc dù lỗi đánh máy của tôi! -) Tx, chỉnh sửa để sửa lỗi. –

+0

Hoàn toàn tắt chủ đề; là! -) cười? – poke

0

Tôi không thấy điều này gây ngạc nhiên, và trên thực tế, nó sẽ hoạt động khi tôi thử nó lần đầu.

Mặc dù không phải tất cả các giá trị đều là bools, lưu ý rằng có hiệu lực, tất cả các giá trị là boolean - chúng đại diện cho giá trị chân lý. (Trong Python, bool là - có hiệu lực - giá trị chỉ đại diện cho đúng hoặc sai.) Số 0 không phải là một bool, nhưng rõ ràng (bằng Python) có giá trị boolean False.

Nói cách khác, toán tử boolean and không phải lúc nào cũng trả về bool, nhưng nó luôn trả về giá trị boolean; một trong số đó thể hiện đúng hoặc sai, ngay cả khi nó cũng có thông tin khác được đính kèm một cách hợp lý vào nó (ví dụ: một chuỗi).

Có thể đây là lý do hồi tố; Tôi không chắc chắn, nhưng một trong hai cách nó có vẻ tự nhiên cho các nhà khai thác boolean của Python để hành xử như họ làm.


Khi nào nên sử dụng?

Trong ví dụ của bạn, test2 cảm thấy rõ ràng hơn với tôi. Tôi có thể nói cả hai đều làm như nhau: việc xây dựng trong test2 không làm cho nó khó hiểu hơn. Tất cả khác bằng nhau, mã ngắn gọn hơn trong test2 là - nhẹ - nhanh chóng được hiểu rõ hơn. Điều đó nói rằng, đó là một sự khác biệt tầm thường, và tôi không thích hoặc là đủ mà tôi muốn nhảy để viết lại bất cứ điều gì.

Nó có thể hữu ích tương tự theo những cách khác:

a = { 
    "b": a and a.val, 
    "c": b and b.val2, 
    "d": c and c.val3, 
} 

Điều này có thể được viết lại cách khác nhau, nhưng điều này là rõ ràng, đơn giản và ngắn gọn.

Đừng quá nhiệt tình; "a() và b() hoặc c()" như là một thay thế cho "a()? b(): c()" là nguy hiểm và khó hiểu, vì bạn sẽ kết thúc với c() nếu b() là sai. Nếu bạn đang viết một câu lệnh terniary, hãy sử dụng cú pháp terniary, mặc dù nó rất xấu xí: b() if a() else c().

+0

Tôi muốn nói rằng test2 không làm cho khó hiểu hơn nếu người đọc không quen thuộc với chủ đề này. Thực tế là chủ đề đang được thảo luận nói với tôi rằng rõ ràng nếu/người nào khác dễ hiểu hơn. –

+1

@Russell Borogove: Đối với bất kỳ bit nào của cú pháp, có ai đó ở đó, những người không hiểu nó và nhiều người khác thảo luận về nó. Đây là tiểu học trong Python (và một số ngôn ngữ khác; Python không phát minh ra điều này), và trừ khi bạn đang viết mã hướng dẫn có nghĩa là cho mẫu số chung ít nhất của lập trình viên mới làm quen, tôi nghĩ rằng điều này là tốt. –

0

Về cơ bản, a and b trả về toán hạng có cùng giá trị chân lý với toàn bộ biểu thức.

Nó có thể âm thanh một chút bối rối nhưng chỉ làm điều đó trong đầu của bạn: Nếu aFalse, sau đó b không quan trọng nữa (vì False and anything sẽ luôn luôn được False), vì vậy nó có thể trở lại a ngay lập tức.

Nhưng khi aTrue thì chỉ b vấn đề, vì vậy nó trả về b ngay lập tức mà không cần tìm kiếm.

Đây là một tối ưu hóa rất phổ biến và rất cơ bản mà nhiều ngôn ngữ thực hiện.

+0

Tôi biết về đánh giá ngắn mạch, nó chỉ là khả năng của biểu thức này có các loại trả lại hoàn toàn khác nhau làm phiền tôi. – NullUserException

+1

@NullUserException: Không hoàn toàn khác biệt chút nào. Giá trị tương đương boolean là như nhau. –

3

trường hợp sử dụng khác của việc này là gì,

số

lý do căn bản để thực hiện chứ không phải unintuitive này là gì?

"không trực quan"? Có thật không? Tôi không đồng ý.

Hãy suy nghĩ.

"a b" bị giả mạo nếu a là sai. Vì vậy, giá trị sai đầu tiên là đủ để biết câu trả lời. Tại sao phải chuyển đổi a sang boolean khác? Nó đã sai rồi. Có bao nhiêu sai hơn là False? Tương tự sai, phải không?

Vì vậy, a giá trị của - khi tương đương với False - là đủ sai, do đó, đó là giá trị của toàn bộ biểu thức. Không chuyển đổi hoặc xử lý thêm. Làm xong.

Khi giá trị của a tương đương với True thì giá trị của tất cả là bắt buộc. Không chuyển đổi hoặc xử lý thêm. Tại sao chuyển đổi b sang boolean khác? Đó là tất cả những gì chúng ta cần biết. Nếu nó là bất cứ thứ gì như True, thì đó là sự thật. Có bao nhiêu sự thật là True?

Tại sao tạo các đối tượng bổ sung giả mạo?

Phân tích tương tự cho hoặc.

Tại sao chuyển sang Boolean? Nó đã đủ đúng hay sai rồi. Làm thế nào nhiều hơn nó có thể nhận được nó?


Hãy thử tính năng này.

>>> False and 0 
False 
>>> True and 0 
0 
>>> (True and 0) == False 
True 

Trong khi (True and 0) thực sự là 0, nó tương đương với False. Đó là sai-đủ cho tất cả các mục đích thực tế.

Nếu đó là sự cố, thì bool(a and b) sẽ buộc chuyển đổi rõ ràng.

+0

Theo một cách nào đó, nó có ý nghĩa +1 – NullUserException

0

Tôi nghĩ rằng trong khi ký hiệu 'hoạt động' nó thể hiện một phong cách mã hóa kém che giấu logic và sẽ gây nhầm lẫn cho những lập trình viên có kinh nghiệm hơn, những người sẽ có 'hành lý' kiến ​​thức về cách đa số các ngôn ngữ khác hoạt động.

Trong hầu hết các ngôn ngữ, giá trị trả lại của hàm đang hoạt động được xác định theo loại hàm. Trừ khi nó bị quá tải một cách rõ ràng. Ví dụ một hàm kiểu 'strlen' được dự kiến ​​sẽ trả về một số nguyên không phải là một chuỗi.

Trong các chức năng của dòng như hàm lõi và hàm logic (+ -/* | &!) Thậm chí còn hạn chế hơn vì chúng cũng có lịch sử lý thuyết toán học chính thức đằng sau chúng. (Hãy suy nghĩ về tất cả các đối số về thứ tự hoạt động cho các chức năng này)

Để có các chức năng cơ bản trả về bất cứ điều gì, nhưng loại dữ liệu phổ biến nhất của chúng (logic hoặc số) phải được phân loại là obfuscation có mục đích.

Chỉ bằng mọi ngôn ngữ phổ biến '&' hoặc '& &' hoặc 'AND' là logic hoặc hàm Boolean.Đằng sau hậu trường, các trình biên dịch tối ưu có thể sử dụng logic cắt ngắn như ở trên trong LOGIC FLOW nhưng không phải DATA STRUCTURE Modification (bất kỳ trình biên dịch tối ưu nào đã thay đổi giá trị theo cách này sẽ bị coi là bị hỏng), nhưng nếu giá trị được dự kiến ​​sẽ được sử dụng trong một biến để tiếp tục xử lý, nó phải ở dạng logic hoặc boolean vì đó là 'chính thức' cho các toán tử này trong phần lớn các trường hợp.

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