Канонічний спосіб повернення декількох значень на мовах, які його підтримують, часто тупірує .
Варіант: Використання кортежу
Розглянемо цей тривіальний приклад:
def f(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return (y0, y1, y2)
Однак це швидко стає проблематичним, оскільки кількість повернених значень збільшується. Що робити, якщо ви хочете повернути чотири-п’ять значень? Звичайно, ви могли б продовжувати їх обробляти, але легко забути, яке значення є де. Також досить некрасиво розпакувати їх там, де ви хочете їх отримати.
Варіант: Використання словника
Наступним логічним кроком, здається, є введення якогось "позначення запису". У Python очевидний спосіб зробити це за допомогою a dict
.
Розглянемо наступне:
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return {'y0': y0, 'y1': y1 ,'y2': y2}
(Щоб було зрозуміло, y0, y1 та y2 позначаються лише як абстрактні ідентифікатори. Як зазначалося, на практиці ви використовуєте значущі ідентифікатори.)
Тепер у нас є механізм, за допомогою якого ми можемо проектувати певного члена повернутого об'єкта. Наприклад,
result['y0']
Варіант: Використання класу
Однак є й інший варіант. Натомість ми могли б повернути спеціалізовану структуру. Я поставив це в контексті Python, але впевнений, що це стосується і інших мов. Дійсно, якби ви працювали в C, це, можливо, буде вашим єдиним варіантом. Ось:
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)
У Python попередні два, можливо, дуже схожі з точки зору сантехніки - адже вони в { y0, y1, y2 }
кінцевому підсумку є записами у внутрішній __dict__
частині ReturnValue
.
Є ще одна додаткова функція, що надається Python, хоча для крихітних об'єктів - __slots__
атрибут. Клас можна виразити так:
class ReturnValue(object):
__slots__ = ["y0", "y1", "y2"]
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
__slots__
Декларація приймає послідовність змінних екземпляра і резервів тільки досить місця в кожному окремому випадку для зберігання значення для кожної змінної. Простір економиться, оскільки__dict__
не створюється для кожного примірника.
Варіант: Використання класу даних (Python 3.7+)
Використовуючи нові класи даних Python 3.7, повертайте клас із автоматично доданими спеціальними методами, набором тексту та іншими корисними інструментами:
@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)
Варіант: Використання списку
Ще одна пропозиція, яку я не помітив, походить від Білла Ящера:
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
Але це мій найулюбленіший метод. Я вважаю, що я зіпсований експозицією до Haskell, але думка про списки змішаного типу завжди відчувала мені незручність. У цьому конкретному прикладі список - не змішаний тип, але він, можливо, може бути.
Список, використаний таким чином, насправді не отримує нічого стосовно кортежу, наскільки я можу сказати. Єдина реальна різниця між списками та кортежами в Python полягає в тому, що списки є змінними , тоді як кортежі - ні.
Я особисто схильний переносити конвенції з функціонального програмування: використовувати списки для будь-якої кількості елементів одного типу і кортежі для фіксованої кількості елементів заздалегідь визначених типів.
Питання
Після тривалої преамбули постає неминуче питання. Який метод (на вашу думку) найкращий?
y3
, яка також зробить ту саму роботу.
y3
, але якщо y3 не оголошено глобальним, це може призвести доNameError: global name 'y3' is not defined
просто використання3
?