Có một quy ước để trả lại nhiều mặt hàng?


10

Trong Python cụ thể (tôi không biết nếu điều này khái quát hóa) có cách nào "tốt nhất" để trả về nhiều mục từ một hàm không?

def func1():
    return a,b #equivalent to (a,b)

def func2():
    return[a,b]

def func3():
    return{"valueA":a,"valueB":b}

Đầu tiên là những gì tôi thấy chung nhất, nhưng tôi cảm thấy như cái cuối cùng tạo ra mã dễ đọc hơn bởi vì bạn đã đặt tên đầu ra, nhưng tôi có thể thiếu một số loại chi phí được tạo bởi phương thức này?


Bạn không trả lời nhiều đối số; trong tất cả các ví dụ này, bạn sẽ trả về một kết quả duy nhất là kiểu dữ liệu hỗn hợp (một tuple, danh sách và từ điển, tương ứng). Kiểu dữ liệu nào để trả về tùy thuộc vào chức năng của bạn và cách sử dụng của nó.
vườn

Thật thú vị, tôi chưa bao giờ nghĩ về nó theo cách đó, nếu bạn đưa ra câu trả lời tôi có thể chấp nhận nó
Devon Muraoka

Câu trả lời:


13

Tôi nghĩ rằng các lựa chọn cần phải được xem xét một cách nghiêm túc theo quan điểm của người gọi: người tiêu dùng có khả năng cần phải làm gì nhất?

Và các tính năng nổi bật của mỗi bộ sưu tập là gì?

  • Các tuple được truy cập theo thứ tự và bất biến
  • Danh sách được truy cập theo thứ tự và có thể thay đổi
  • Dict được truy cập bằng khóa

Danh sách và bộ dữ liệu tương đương với quyền truy cập, nhưng danh sách có thể thay đổi. Chà, điều đó không quan trọng với tôi người gọi nếu tôi sẽ giải nén ngay kết quả:

score, top_player = play_round(players)
# or
idx, record = find_longest(records)

Không có lý do nào ở đây để tôi quan tâm nếu đó là một danh sách hay một tuple, và bộ dữ liệu đơn giản hơn ở cả hai bên.

Mặt khác, nếu bộ sưu tập được trả lại sẽ được giữ nguyên và được sử dụng làm bộ sưu tập :

points = calculate_vertices(shape)
points.append(another_point)
# Make a new shape

sau đó nó có thể có ý nghĩa cho sự trở lại là có thể thay đổi. Tính đồng nhất cũng là một yếu tố quan trọng ở đây. Giả sử bạn đã viết một hàm để tìm kiếm một chuỗi các mẫu lặp lại. Thông tin tôi nhận được là chỉ mục trong chuỗi phiên bản đầu tiên của mẫu, số lần lặp lại và chính mẫu đó. Những thứ đó không giống nhau. Mặc dù tôi có thể giữ các mảnh lại với nhau, không có lý do gì mà tôi muốn thay đổi bộ sưu tập . Đây không phải là một list.

Bây giờ cho từ điển.

mã cuối cùng tạo mã dễ đọc hơn vì bạn đã đặt tên đầu ra

Đúng, có các khóa cho các trường làm cho dữ liệu không đồng nhất rõ ràng hơn, nhưng nó cũng đi kèm với một số trở ngại. Một lần nữa, đối với trường hợp "Tôi sẽ giải nén các thứ", điều này

round_results = play_round(players)
score, top_player = round_results["score"], round_results["top_player"]

(ngay cả khi bạn tránh các chuỗi ký tự cho các phím), là công việc bận rộn không cần thiết so với phiên bản tuple.

Câu hỏi ở đây gồm ba phần: bộ sưu tập phức tạp đến mức nào, bộ sưu tập sẽ được giữ cùng nhau trong bao lâu và chúng ta có cần sử dụng cùng loại bộ sưu tập này ở một loạt các địa điểm khác nhau không?

Tôi muốn đề xuất rằng giá trị trả về truy cập có khóa bắt đầu có ý nghĩa hơn một tuple khi có nhiều hơn khoảng ba thành viên và đặc biệt là nơi có lồng nhau:

shape["transform"]["raw_matrix"][0, 1] 
# vs.
shape[2][4][0, 1]

Điều đó dẫn đến câu hỏi tiếp theo: bộ sưu tập sẽ giữ nguyên phạm vi này, ở đâu đó ngoài cuộc gọi đã tạo ra nó? Truy cập khóa trên đó hoàn toàn sẽ giúp dễ hiểu.

Câu hỏi thứ ba - tái sử dụng - chỉ ra một kiểu dữ liệu tùy chỉnh đơn giản như một tùy chọn thứ tư mà bạn không trình bày.

Là cấu trúc chỉ thuộc sở hữu của một chức năng này? Hay bạn đang tạo cùng một bố cục từ điển ở nhiều nơi? Do nhiều phần khác của chương trình cần phải hoạt động trên cấu trúc này? Một bố cục từ điển lặp đi lặp lại nên được đưa vào một lớp. Phần thưởng là bạn có thể đính kèm hành vi: có thể một số chức năng hoạt động trên dữ liệu được gói gọn dưới dạng phương thức.

Một lựa chọn thứ năm tốt, nhẹ, là namedtuple(). Đây thực chất là dạng bất biến của giá trị trả về từ điển.


Có một lý do nào bạn không đề cập đến các trường hợp của các lớp do người dùng định nghĩa không? Đó phải là giải pháp goto trong bất kỳ ngôn ngữ OO nào.
Esben Skov Pedersen

1
Điều đó được đề cập trong các đoạn thứ ba đến cuối cùng và từ thứ hai đến cuối cùng, @EsbenSkovPedersen. "Một bố cục từ điển lặp đi lặp lại nên được đưa vào một lớp."
jscs

1

Đừng nghĩ về các hàm trả về nhiều đối số. Về mặt khái niệm, tốt nhất là nghĩ về các hàm là cả nhận và trả về một đối số duy nhất. Một hàm xuất hiện để chấp nhận nhiều đối số thực sự chỉ nhận được một đối số duy nhất của loại tuple (chính thức là sản phẩm ). Tương tự, một hàm trả về nhiều đối số chỉ đơn giản là trả về một tuple.

Trong Python:

def func(a, b, c):
  return b, c

có thể được viết lại như

def func(my_triple):
  return (my_triple[1], my_triple[2])

để làm cho sự so sánh rõ ràng.

Trường hợp đầu tiên chỉ đơn thuần là cú pháp đường cho cái sau; cả hai đều nhận được một bộ ba như là một đối số, nhưng mẫu đầu tiên - khớp với đối số của nó để thực hiện hủy tự động vào các thành phần cấu thành của nó. Do đó, ngay cả các ngôn ngữ không có khớp mẫu chung đầy đủ cũng thừa nhận một số dạng khớp mẫu cơ bản trên một số loại của chúng (Python thừa nhận khớp mẫu trên cả hai loại sản phẩm và bản ghi).


Để trở lại câu hỏi trong tầm tay: không có câu trả lời duy nhất cho câu hỏi của bạn, bởi vì nó sẽ giống như hỏi "kiểu trả về của hàm tùy ý" là gì? Nó phụ thuộc vào chức năng và trường hợp sử dụng. Và, tình cờ, nếu "nhiều giá trị trả về" thực sự độc lập, thì có lẽ chúng nên được tính bằng các hàm riêng biệt.

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.