Простой Python. Современный стиль программирования (Любанович) - страница 64

В этот раз мы вызовем функцию menu(), не передав ей аргумент dessert:

>>>> menu('chardonnay', 'chicken')

>{'dessert': 'pudding', 'wine': 'chardonnay', 'entree': 'chicken'}

Если вы предоставите аргумент, он будет использован вместо аргумента по умолчанию:

>>>> menu('dunkelfelder', 'duck', 'doughnut')

>{'dessert': 'doughnut', 'wine': 'dunkelfelder', 'entree': 'duck'}


Значение аргументов по умолчанию высчитывается, когда функция определяется, а не выполняется. Распространенной ошибкой новичков (и иногда не совсем новичков) является использование изменяемого типа данных вроде списка или словаря в качестве аргумента по умолчанию.


В следующей проверке ожидается, что функция buggy() будет каждый раз запускаться с новым пустым списком result, добавлять в него аргумент arg, а затем выводить на экран список, состоящий из одного элемента. Однако в этой функции есть баг: список будет пуст только при первом вызове. Во второй раз список result будет содержать элемент, оставшийся после предыдущего вызова:

>>>> def buggy(arg, result=[]):

>…·····result.append(arg)

>…·····print(result)

>…

>>>> buggy('a')

>['a']

>>>> buggy('b')···# ожидаем увидеть ['b']

>['a', 'b']

Функция работала бы корректно, если бы код выглядел так:

>>>> def works(arg):

>…·····result = []

>…·····result.append(arg)

>…·····return result

>…

>>>> works('a')

>['a']

>>>> works('b')

>['b']

Решить проблему можно, передав в функцию что-то еще, чтобы указать на то, что вызов является первым:

>>>> def nonbuggy(arg, result=None):

>…·····if result is None:

>…·········result = []

>…·····result.append(arg)

>…·····print(result)

>…

>>>> nonbuggy('a')

>['a']

>>>> nonbuggy('b')

>['b']

Получаем позиционные аргументы с помощью *

Если вы работали с языками программирования C или C++, то можете предположить, что астериск (*) в Python как-то относится к указателям. Это не так, Python не имеет указателей.

Если символ * будет использован внутри функции с параметром, произвольное количество позиционных аргументов будет сгруппировано в кортеж. В следующем примере args является кортежем параметров, который был создан из аргументов, переданных в функцию print_args():

>>>> def print_args(*args):

>…·····print('Positional argument tuple:', args)

>…

Если вы вызовете функцию без аргументов, то получите пустой кортеж:

>>>> print_args()

>Positional argument tuple: ()

Все аргументы, которые вы передадите, будут выведены на экран как кортеж args:

>>>> print_args(3, 2, 1, 'wait!', 'uh…')

>Positional argument tuple: (3, 2, 1, 'wait!', 'uh…')

Это полезно при написании функций вроде print(), которые принимают произвольное количество аргументов. Если в вашей функции имеются также обязательные позиционные аргументы, *args отправится в конец списка и получит все остальные аргументы: