Kiểu nào sẽ được sử dụng cho các tham số trả về không được sử dụng trong lệnh gọi hàm Python


30

Có kiểu mã hóa nào được đề xuất / thường được chấp nhận để xử lý các tình huống trong đó hàm trả về một tuple giá trị không nhưng chỉ một trong những giá trị đó được sử dụng sau đó (lưu ý rằng điều này chủ yếu dành cho các hàm thư viện mà tôi không thể thay đổi - viết một trình bao bọc xung quanh Cuộc gọi có lẽ là một chút quá mức cần thiết? Thay vì làm

a, b, c = foo()

và sau đó chỉ không sử dụng bc, biến thể nào sau đây nên được ưu tiên (hoặc có biến thể nào khác không?):

Biến thể 1 (gạch dưới)

a, _, _ = foo()

(rất rõ ràng và đơn giản nhưng có thể xung đột với việc _ = gettext.gettextsử dụng trong nhiều ứng dụng sử dụng dịch thuật)

Biến thể 2 (tên giả)

a, unused, unused = foo()

(tôi không hấp dẫn lắm, tôi nghĩ, tương tự với các tên khác như dummy)

Biến 3 (chỉ mục)

a = foo()[0]

(với tôi ()[0]vẻ ngoài không giống pythonic)


Nó trái ngược với câu trả lời trước đây của tôi, điều gì xảy ra với biến thể 3 khi bạn muốn tham khảo 2/3 giá trị trả về? Tôi đã xóa câu trả lời của mình vì tôi nhận ra mình không biết đủ về Python để biện minh cho nó.
Craige

@Craige: Tôi không thấy câu trả lời của bạn trước khi bạn xóa nó ... Bạn có hỏi liệu a, b = foo()[0:2]có hoạt động không? Nếu có: có, đúng vậy :)
user49643

Đó chính xác là những gì tôi đã hỏi. Nếu nó hoạt động (như bạn đã nói) Tôi sẽ sử dụng biến thể 3. Tôi đang kích hoạt lại câu trả lời của mình với thông tin này.
Craige

3
Ngẫu nhiên, những ngày này, bạn có thể sử dụng cú pháp khá đẹp để giải nén 'mở rộng' : a, *_ = foo()sẽ loại bỏ tất cả các giá trị ngoại trừ giá trị đầu tiên.
Benjamin Hodgson

Câu trả lời:


17

Sử dụng dấu gạch dưới cho các biến không sử dụng chắc chắn là chấp nhận được. Mặc dù được cảnh báo, trong một số cơ sở mã, nó không phải là một tùy chọn vì định danh đó được dành riêng như tốc ký gettext. Đây là sự phản đối thường xuyên nhất đối với phong cách này (mặc dù nó không phải là vấn đề đối với đa số theo như tôi có thể đánh giá). Tôi vẫn khuyên bạn nên và luôn luôn sử dụng nó.

Những cái tên như dummyhoặc unusedcó xu hướng gây khó chịu cho cá nhân tôi và tôi không thấy chúng thường xuyên (trong Python, nghĩa là - tôi biết một cơ sở mã Delphi sử dụng dummytự do, và nó cũng đã bị rò rỉ vào các tập lệnh liên quan đến chương trình được đề cập). Tôi khuyên bạn chống lại nó.

Chỉ cần trích xuất một mục từ tuple trả lại là được. Nó cũng tiết kiệm một số rắc rối với việc lấy đúng số lượng giá trị không sử dụng. Lưu ý rằng mặc dù nó có hai nhược điểm tiềm năng:

  • Nó sẽ không nổ tung nếu số lượng giá trị khác với những gì bạn mong đợi. Điều này thể hữu ích để phát hiện hỗn hợp và lỗi chính tả.
  • Nó chỉ hoạt động khi giá trị trả về là một chuỗi (phần lớn là các bộ và danh sách, nhưng hãy giữ nguyên chung). Chính thức, tôi biết một lớp trong mã của mình (vectơ 2D) có thể lặp lại và mang lại số lượng giá trị không đổi (và do đó có thể được sử dụng trong việc giải nén các bài tập), nhưng không thể lập chỉ mục được.

Tôi thực sự đã đề cập đến gettext trong câu hỏi của mình :) Dù sao, tôi đã chấp nhận câu trả lời của bạn - có vẻ như không có phong cách nào được chấp nhận rõ ràng nhưng câu trả lời của bạn nêu lên một số điểm thú vị.
dùng49643

Để tránh các vấn đề với gettext (hoặc để tránh các vấn đề tương tự trong trình thông dịch), bạn có thể sử dụng dấu gạch dưới kép (còn gọi là dunders) thay vì đơn.
Zim

21

Pylint đã cho tôi thói quen làm theo cách này:

widget, _parent, _children = f()

Đó là, kết quả không được sử dụng có tên mô tả có tiền tố là _. Pylint liên quan đến người dân địa phương có tiền tố _ là không được sử dụng và toàn cầu hoặc thuộc tính có tiền tố là _ là riêng tư.


3

Nếu trong toàn bộ dự án của bạn, bạn chỉ thực hiện việc này một lần hoặc rất hiếm khi thực hiện chức năng cụ thể, tôi sẽ sử dụng Biến thể 1 nếu bạn biết gettextkhông phải là sự cố trong mô-đun đó, và nếu không là Biến thể 3.

Mặt khác, nếu bạn đã làm điều này rất nhiều - và đặc biệt là nếu mỗi lần bạn muốn có một tập hợp con khác của các giá trị trả về (tạo một trình bao bọc để trả về các giá trị bạn quan tâm không khả thi), có thể có ích khi viết một trình bao bọc mà đặt các kết quả vào một tuple có tên hoặc một thể hiện của một số lớp mô tả khác, điều này sẽ cho phép bạn làm:

bar = foo()

Và sau đó làm việc với bar.a, bar.bbar.c.


2

Như những người khác đã nói, gạch dưới ( _) là tiêu chuẩn. Nhưng nếu gạch dưới đang được sử dụng để dịch, tôi nghĩ rằng gạch dưới gấp đôi là cách thay thế tốt nhất.

var, __, value = "VAR=value".partition('=')

Tốt hơn những thứ này:

var, unused, value = "VAR=value".partition('=')

var, unused_del, value = "VAR=value".partition('=')

var, _del, value = "VAR=value".partition('=')


1

Tôi là một lập trình viên không phải là Python, nhưng với tôi, biến thể thứ ba có ý nghĩa nhất.

Trong biến thể 3, bạn hoàn toàn rõ ràng những giá trị mà bạn quan tâm để giải quyết. Trong biến thể 1 và 2, bạn đang gán các giá trị lại cho các biến và do đó, chúng có thể được sử dụng. Bạn có thể đã đặt tên cho chúng một cách khó hiểu, nhưng việc đặt tên kém không thực sự là một giải pháp cho bất kỳ vấn đề nào.

Ngoài sự rõ ràng, tại sao bạn muốn gán các giá trị không sử dụng cho một vị trí trong bộ nhớ (như trong các biến thể 1 và 2)? Đây sẽ là một giải pháp kém về mặt quản lý bộ nhớ.


Nếu bạn luôn đặt nó trên cùng một biến thì vấn đề bộ nhớ sẽ chỉ là kích thước của một biến duy nhất tại bất kỳ thời điểm nào? Tôi không nghĩ đó là một vấn đề.
Michael McQuade

-2

Đây là một quy tắc chung: Nếu chỉ có 1 trong số các giá trị được trả về được sử dụng, tại sao không trả về 1 giá trị đó? Trong trường hợp cờ được gọi từ nhiều nơi, hãy giữ một cờ cho cùng và trả về các giá trị theo cờ.

CHỈNH SỬA:

Trong trường hợp tôi ở trong hoàn cảnh của bạn và tôi đã không viết hàm, có lẽ tôi sẽ sử dụng Biến thể 2. Tôi sẽ giữ các tên giả ở đó để các tham số có thể được sử dụng trong trường hợp cần phát sinh. Cắt một danh sách sẽ có một chút chi phí. Có lẽ bạn có thể dành một vài byte để nhận dữ liệu không mong muốn.


-1 Tôi đoán anh ta đã không xác định chức năng và do đó không thể thay đổi những gì nó trả về. Tôi nghĩ rằng anh ta đang đề cập đến khi hàm trả về 3 giá trị, nhưng anh ta chỉ quan tâm đến 1 trong trường hợp sử dụng hiện tại của mình.
Craige

@Craige: Vâng, ý tôi là các chức năng tôi không thể thay đổi - Tôi đã thêm một ghi chú cho câu hỏi của mình để làm rõ điều đó.
dùng49643

Bạn có chắc chắn về chi phí không? Tôi đã thử một thử nghiệm ipython rất đơn giản: %timeit a, _, _ = foo()so với %timeit a = foo()[0]kết quả là 123ns so với 109ns, tức là việc cắt lát dường như thực sự nhanh hơn so với việc giải nén giá trị. Hay bạn có bất kỳ tình huống cụ thể trong tâm trí?
dùng49643

2
Một kịch bản hợp lý khác là bạn không cần tất cả các giá trị cho một số cuộc gọi.
Keith Thompson
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.