Cách chính tắc để trả về nhiều giá trị trong các ngôn ngữ hỗ trợ nó thường là tupling .
Tùy chọn: Sử dụng bộ dữ liệu
Hãy xem xét ví dụ tầm thường này:
def f(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return (y0, y1, y2)
Tuy nhiên, điều này nhanh chóng gặp vấn đề khi số lượng giá trị được trả về tăng lên. Điều gì nếu bạn muốn trả về bốn hoặc năm giá trị? Chắc chắn, bạn có thể tiếp tục sử dụng chúng, nhưng thật dễ dàng để quên giá trị đó ở đâu. Nó cũng khá xấu xí để giải nén chúng bất cứ nơi nào bạn muốn nhận chúng.
Tùy chọn: Sử dụng từ điển
Bước hợp lý tiếp theo dường như là giới thiệu một số loại 'ký hiệu hồ sơ'. Trong Python, cách rõ ràng để làm điều này là bằng cách a dict
.
Hãy xem xét những điều sau đây:
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return {'y0': y0, 'y1': y1 ,'y2': y2}
(Nói rõ hơn, y0, y1 và y2 chỉ có nghĩa là các định danh trừu tượng. Như đã chỉ ra, trong thực tế, bạn sử dụng các định danh có ý nghĩa.)
Bây giờ, chúng ta có một cơ chế theo đó chúng ta có thể chiếu ra một thành viên cụ thể của đối tượng được trả về. Ví dụ,
result['y0']
Tùy chọn: Sử dụng một lớp
Tuy nhiên, có một lựa chọn khác. Thay vào đó chúng ta có thể trả về một cấu trúc chuyên biệt. Tôi đã đóng khung cái này trong ngữ cảnh của Python, nhưng tôi chắc chắn nó cũng áp dụng cho các ngôn ngữ khác. Thật vậy, nếu bạn đang làm việc trong C thì đây rất có thể là lựa chọn duy nhất của bạn. Đây là:
class ReturnValue:
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return ReturnValue(y0, y1, y2)
Trong Python, hai cái trước có lẽ rất giống nhau về hệ thống ống nước - sau khi tất cả { y0, y1, y2 }
cuối cùng chỉ là mục trong nội bộ __dict__
của ReturnValue
.
Có một tính năng bổ sung được cung cấp bởi Python mặc dù đối với các đối tượng nhỏ, __slots__
thuộc tính. Các lớp có thể được thể hiện như sau:
class ReturnValue(object):
__slots__ = ["y0", "y1", "y2"]
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
Từ tài liệu tham khảo Python :
Các
__slots__
tuyên bố mất một chuỗi các biến dụ và dự trữ chỉ đủ không gian trong mỗi trường hợp để giữ giá trị cho mỗi biến. Không gian được lưu vì__dict__
không được tạo cho mỗi phiên bản.
Tùy chọn: Sử dụng một dataclass (Python 3.7+)
Sử dụng các bảng dữ liệu mới của Python 3.7, trả về một lớp với các phương thức đặc biệt được thêm tự động, gõ và các công cụ hữu ích khác:
@dataclass
class Returnvalue:
y0: int
y1: float
y3: int
def total_cost(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return ReturnValue(y0, y1, y2)
Tùy chọn: Sử dụng danh sách
Một đề nghị khác mà tôi đã bỏ qua đến từ Bill the Lizard:
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
Đây là phương pháp ít yêu thích nhất của tôi mặc dù. Tôi cho rằng tôi đã bị vấy bẩn khi tiếp xúc với Haskell, nhưng ý tưởng về danh sách hỗn hợp luôn khiến tôi cảm thấy khó chịu. Trong ví dụ cụ thể này, danh sách là loại hỗn hợp, nhưng có thể hiểu được.
Một danh sách được sử dụng theo cách này thực sự không đạt được bất cứ điều gì liên quan đến bộ dữ liệu như tôi có thể nói. Sự khác biệt thực sự duy nhất giữa danh sách và bộ dữ liệu trong Python là danh sách có thể thay đổi , trong khi bộ dữ liệu thì không.
Cá nhân tôi có xu hướng thực hiện các quy ước từ lập trình chức năng: sử dụng danh sách cho bất kỳ số lượng phần tử nào cùng loại và bộ dữ liệu cho một số phần tử cố định của các loại được xác định trước.
Câu hỏi
Sau lời mở đầu dài, đến câu hỏi không thể tránh khỏi. Phương pháp nào (bạn nghĩ) là tốt nhất?
y3
, điều đó cũng sẽ làm công việc tương tự.
y3
, nhưng trừ khi y3 được khai báo toàn cầu, điều này có thể mang lạiNameError: global name 'y3' is not defined
chỉ là sử dụng3
?