Стойности по подразбиране
Проблем
Две покупки, три покупки
Касата трябва да сумира цените на покупките. Понякога са две, понякога три. Функцията е една и съща по смисъл: „сумирай“. В Java и C# това се прави с два метода с едно име и различен брой параметри. Пробваш същото:
def total(a, b): return a + b
def total(a, b, c): return a + b + c
print(total(2.5, 4.0, 1.5))print(total(2.5, 4.0))8.0С три аргумента работи. С два програмата спира:
TypeError: total() missing 1 required positional argument: 'c'Python казва, че на total липсва c. Значи вика функцията с трите параметъра. Къде отиде първата?
Идеята
Едно име, една функция
В Python def е команда като всички останали. Изпълнява се, когато програмата стигне до нея, и записва функцията под име. Второ def със същото име записва нова функция под същото име, а старата се губи. Кое def е последно преди извикването, това решава коя функция работи.
Затова Python няма претоварване (overloading): две функции с едно име, които се различават по параметрите, както в Java и C#. Вместо това една функция може да приема различен брой аргументи. Как, ще видиш в следващите карти.
def print_header(): print("Квартален магазин")
print_header()
def print_header(): print("Магазин „Център“")
print_header()Стъпка по стъпка, с думи
- def записва функцията под името print_header. Името сочи нея.
- Извикване: името сочи първата функция и тя печата „Квартален магазин“.
- Второто def прави нова функция и насочва същото име към нея. Първата я няма.
- Второто извикване: „Магазин „Център““.
- Името е едно. Последното def, до което е стигнала програмата, решава коя функция се вика.
Пробвай
Коя функция?
Какво ще отпечата програмата?
def describe(x): print(f"цяло: {x}")
def describe(x): print(f"дробно: {x}")
describe(5)describe(5.0)def describe е заместило първото, затова и двете извиквания стигат до „дробно“. Python не избира функция по типа на аргумента: 5 и 5.0 отиват в една и съща функция.Идеята
Стойност по подразбиране
Една функция стига и за две, и за три покупки. Дай на третия параметър стойност по подразбиране: тя се ползва, когато аргументът не е подаден.
def total(a, b, c=0): return a + b + c
print(total(2.5, 4.0))print(total(2.5, 4.0, 1.5))6.58.0c=0 значи: ако при извикването има само два аргумента, c е 0. Ако има три, c е третият.
В Python около = в стойността по подразбиране не се слагат интервали: c=0. Така пише ръководството PEP 8.
Параметрите със стойност по подразбиране се пишат след тези без такава. Аргументите се свързват с параметрите по място, затова незадължителните стоят накрая.
По-точно, за любопитните
Стойността по подразбиране се смята веднъж, когато Python стигне до def, а не при всяко извикване. За числа и текст това няма значение. Но списък по подразбиране е един и същ за всички извиквания:
def add_item(item, cart=[]): cart.append(item) return cart
print(add_item("хляб"))print(add_item("мляко"))['хляб']['хляб', 'мляко']Второто извикване продължава списъка на първото. Затова за списък по подразбиране се пише None и списъкът се прави във функцията:
def add_item(item, cart=None): if cart is None: cart = [] cart.append(item) return cart
print(add_item("хляб"))print(add_item("мляко"))['хляб']['мляко']Пробвай
Намери грешката
SyntaxError, преди да изпълни и един ред. На кой ред е грешката?Избери реда с грешката.
nights=1) е преди параметъра без такава (name). Python го забранява: „parameter without a default follows parameter with a default“. Поправката е def book(name, nights=1):.Идеята
Аргументи по име
Хотелът записва резервации. Една нощувка без закуска е най-честата, затова двете са по подразбиране:
def book(name, nights=1, breakfast=False): print(f"{name}, нощувки: {nights}") if breakfast: print(" със закуска")
book("Мария")book("Иван", 3)book("Петя", breakfast=True)book(nights=2, name="Георги")Мария, нощувки: 1Иван, нощувки: 3Петя, нощувки: 1 със закускаГеорги, нощувки: 2Петя иска закуска, но една нощувка. Не е нужно да пишеш нощувките: breakfast=True подава аргумента по име, направо на параметъра breakfast. Това се казва аргумент по име (keyword argument). С имена редът няма значение: Георги подава и двата аргумента по име, в обратен ред.
Името трябва да е точно. Сгрешено име не минава тихо, а спира програмата:
book("Мария", night=2)
TypeError: book() got an unexpected keyword argument 'night'По-точно, за любопитните
- След аргумент по име не може да има аргумент без име:
book(name="Мария", 3)не тръгва („positional argument follows keyword argument“). - Аргументите по име правят извикването по-ясно и когато не пропускаш нищо:
book("Иван", nights=3)се чете по-лесно отbook("Иван", 3).
Идеята
Колкото искаш аргументи
А ако покупките са пет? Двайсет? Не пишеш параметър за всяка. Казваш, че функцията приема произволен брой аргументи:
def total(*prices): result = 0 for p in prices: result += p return result
print(total(1.5, 2.0, 3.5, 4.0))print(total(9.99))print(total())11.09.990Звездичката пред името (*prices) значи: „подай колкото искаш стойности“. Вътре във функцията те пристигат като кортеж (tuple): поредица като списък, която не може да се променя. Без аргументи той е празен.
def show(*prices): print(prices)
show(1.5, 2.0)(1.5, 2.0)Затова и print печата колкото стойности му дадеш: това е една функция, която приема произволен брой аргументи.
print("Хляб", "Мляко", "Кафе")print(max(3, 8, 2))Хляб Мляко Кафе8По-точно, за любопитните
- Такъв параметър може да е само един. Параметрите след него се подават само по име:
def receipt(*prices, currency="€")се вика сreceipt(2.5, 4.0, currency="EUR"). - Има и
**options: той събира аргументите по име в речник. Ще го срещнеш в чужд код.
Пробвай
Какво липсва?
def total(prices):
result = 0
for p in prices:
result += p
return result*prices: звездичката пред името събира всички аргументи.Упражнение
Една функция вместо няколко
1. Най-голямото. Напиши една функция largest(*numbers), която връща най-голямото от колкото и да е числа.
largest(3, 8)largest(4, 9, 2)largest(2.5, 1.5)892.52. Среден успех. Функция average(*grades) връща средното на произволен брой оценки, а без оценки връща 0.
average(5, 6, 4)average(6, 5)average()5.05.503. Ред от бележката. print_line(item, qty) печата „Кафе x 2“. Направи бройката незадължителна: без нея е 1.
print_line("Кафе", 2)print_line("Кроасан")Кафе x 2Кроасан x 14. Безплатна доставка. shipping_cost(total, free_from=50) връща 0, ако поръчката е поне колкото прага, иначе 4,99 €. Прагът е 50 €, ако не е подаден друг.
shipping_cost(62.0)shipping_cost(30.0)shipping_cost(30.0, free_from=25)04.990Тест