Python có hàm “hoặc bằng” như || = trong Ruby không?


82

Nếu không, cách tốt nhất để làm điều này là gì?

Ngay bây giờ tôi đang làm (cho một dự án django):

if not 'thing_for_purpose' in request.session:
    request.session['thing_for_purpose'] = 5

nhưng nó khá khó xử. Trong Ruby, nó sẽ là:

request.session['thing_for_purpose'] ||= 5

đẹp hơn nhiều.


23
Lưu ý rằng hai bit mã này thực sự rất khác nhau: phiên bản Python đặt nó thành 5 nếu nó không có trong dict, trong đó phiên bản Ruby cũng đặt nó thành 5 nếu nó được đặt thành bất kỳ giá trị sai nào.
Glenn Maynard

2
@Glenn, không khác lắm , nhưng khá khác biệt. Vì một giá trị băm chưa được khởi tạo trả về nil(sai trong ngữ cảnh boolean) nên thành ngữ này thường được sử dụng chính xác cho mục đích mà sean đã sử dụng nó. Các thành ngữ chỉ hoạt động mặc dù nếu, dĩ nhiên, nilfalselà những giá trị không hợp pháp trong các hash (đó là rất thường xuyên đúng, vì vậy các thành ngữ là tốt)
horseyguy

8
@banister: Tôi không biết người ta có thể vẽ ranh giới giữa "rất" và "khá" ở đâu, nhưng vấn đề là đây không phải là những câu tương đương và điều quan trọng là phải hiểu sự khác biệt. (False là rất thường xuyên một giá trị hợp lệ trong một hash, mà sẽ cắn bạn khi bạn muốn đặt mặc định cho một lĩnh vực boolean true; đó là một thiếu sót đáng kể của thành ngữ Ruby.)
Glenn Maynard

Có, ví dụ Python gần giống với định nghĩa-hoặc , giống như //=cái mà bạn tìm thấy trong perl . Tôi nghĩ nó ||=cũng bắt nguồn từ Perl.
draegtun 14/10/10

Ah điểm tốt, tất cả. Tôi đã không nhận thấy sự khác biệt này.
Sean W.

Câu trả lời:


186

Câu trả lời được chấp nhận là phù hợp cho các phái, nhưng tiêu đề tìm kiếm một tổng quát tương đương với toán tử || = của Ruby. Một cách phổ biến để làm điều gì đó như || = trong Python là

x = x or new_value

36
Câu trả lời này có thể là những gì những người đến đây từ tìm kiếm của Google đang tìm kiếm.
gradi3nt

Đây thực sự là câu trả lời tốt nhất.
AdamC

6
Lưu ý rằng không giống như trong Ruby, mã này sẽ chỉ hoạt động nếu xđã được xác định trước đó (ví dụ được đặt thành Nonetrong một phương thức khởi tạo lớp).
oli

3
Đúng, điều này không hoạt động chính xác như Ruby's || =. Một điều khác cần chú ý là 'tính trung thực' của x. Nếu x == 0 bằng Python, bạn sẽ nhận được new_value từ 0 được coi là sai, nhưng trong Ruby bạn sẽ nhận được 0.
Joseph Sheedy

1
Điều này có hiệu quả như || = không? || = không thực hiện một phép gán trừ khi nó rỗng, nhưng điều này luôn thực hiện một phép gán. Trình biên dịch python có thông minh hơn tôi nghĩ không?
jsarma

17

dictsetdefault().

Vì vậy, nếu request.sessionlà một dict:

request.session.setdefault('thing_for_purpose', 5)

Hoàn toàn tương tự nhưng không có cách nào tương đương với || = của Ruby.
AdamC

1
Nó khác biệt đáng kể ở chỗ biểu thức mặc định được đánh giá ngay cả khi khóa đã được đặt. Không có cách nào để giải quyết câu hỏi ban đầu mà không đánh giá giá trị mặc định hoặc truy cập khóa nhiều hơn một lần hoặc cả hai.
slinkp

10

Đặt giá trị mặc định có ý nghĩa nếu bạn đang thực hiện nó trong phần mềm trung gian hoặc thứ gì đó, nhưng nếu bạn cần giá trị mặc định trong ngữ cảnh của một yêu cầu:

request.session.get('thing_for_purpose', 5) # gets a default

tiền thưởng: đây là cách thực sự làm một điều ||=trong Python.

def test_function(self, d=None):
    'a simple test function'
    d = d or {}

    # ... do things with d and return ...

10

Câu trả lời chính xác: Không. Python không có một toán tử tích hợp opnào có thể dịch x = x or ysang x op y.

Nhưng, nó gần như không. Toán tử bitwise hoặc-equals ( |=) sẽ hoạt động như mô tả ở trên nếu cả hai toán hạng đang được coi là boolean, với một cảnh báo. (Cảnh báo trước là gì? Tất nhiên là câu trả lời ở bên dưới.)

Đầu tiên, phần trình diễn cơ bản về chức năng:

x = True
x    
Out[141]: True

x |= True
x    
Out[142]: True

x |= False
x    
Out[143]: True

x &= False
x    
Out[144]: False

x &= True
x    
Out[145]: False

x |= False
x    
Out[146]: False

x |= True
x   
Out[147]: True

Lưu ý là do python không được nhập đúng và do đó ngay cả khi các giá trị đang được coi là boolean trong một biểu thức, chúng sẽ không bị đoản mạch nếu được cung cấp cho toán tử bitwise. Ví dụ: giả sử chúng ta có một hàm boolean xóa danh sách và trả về Trueiff có các phần tử bị xóa:

def  my_clear_list(lst):
    if not lst:
        return False
    else:
        del lst[:]
        return True

Bây giờ chúng ta có thể thấy hành vi đoản mạch như sau:

x = True
lst = [1, 2, 3]
x = x or my_clear_list(lst)
print(x, lst)

Output: True [1, 2, 3]

Tuy nhiên, chuyển đổi sang orbitwise hoặc ( |) sẽ loại bỏ ngắn mạch, do đó, hàm my_clear_listthực thi.

x = True
lst = [1, 2, 3]
x = x | my_clear_list(lst)
print(x, lst)

Output: True []

Trên, x = x | my_clear_list(lst)tương đương với x |= my_clear_list(lst).


1

Nói chung, bạn có thể sử dụng dict[key] = dict.get(key, 0) + val.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.