Канонічний спосіб повернення декількох значень на мовах, які його підтримують, часто тупірує .
Варіант: Використання кортежу
Розглянемо цей тривіальний приклад:
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?