<jupyter_start><jupyter_text>Функции<jupyter_code>from datetime import datetime

def get_seconds():
    """Return current seconds"""
    return datetime.now().second

print( get_seconds() )        # Вызов функции
print( get_seconds.__doc__ )  # Получение документационной строки из магического атрибута
print( get_seconds.__name__ ) # Получение имени функции из магического атрибута<jupyter_output>48
Return current seconds
get_seconds<jupyter_text>Чаще всего функция определяется с параметрами. Если эту функцию вызвать без параметров, то выпадет ошибка `TypeError`:<jupyter_code>def split_tags(tag_string):
    tag_list = []
    for tag in tag_string.split(','):
        tag_list.append(tag.strip()) # Обрезаем пробелы и заносим элементы в новый список tag_list

    return tag_list

print( split_tags('python, coursera, mooc') ) # Передаем строку<jupyter_output>['python', 'coursera', 'mooc']<jupyter_text>Аннотация типовВ функции можно указать тип аргументов, а также тип возвращаемого значения:<jupyter_code>def add(x: int, y: int) -> int:
    return x + y<jupyter_output><empty_output><jupyter_text>Ошибки нет, код исполняется, потому что Python это динамический язык и аннотация типов призвана помочь программисту или его IDE отловить какие-то ошибки:<jupyter_code>print( add(10, 11) )
print( add('still ', 'works') )<jupyter_output>21
still works<jupyter_text>По ссылке или по значению?<jupyter_code>def extender(source_list, extend_list):
    return source_list.extend(extend_list)

source_list = [1, 2, 3]
extender(source_list, [4, 5, 6])

print(source_list)<jupyter_output>[1, 2, 3, 4, 5, 6]<jupyter_text>Неизменяемый объект:<jupyter_code>def replacer(source_tuple, replace_with):
    source_tuple = replace_with # Менять значения передаваемых в функцию переменных - дурной тон

user_info = ('Guido', '31/01')
replacer(user_info, ('Larry', '27/09'))

# Объект не изменился, так как tuple() неизменяемый тип
print(user_info)<jupyter_output>('Guido', '31/01')<jupyter_text>Именованные аргументы<jupyter_code>def say(greeting, name):
    print('{} {}!'.format(greeting, name))

# Можно передать аргументы в функцию в другом порядке, указав имя и значение аргумента
say('Hello', 'Kitty')               # Hello Kitty!
say(name='Kitty', greeting='Hello') # Hello Kitty!<jupyter_output>Hello Kitty!
Hello Kitty!<jupyter_text>Область видимости<jupyter_code>result = 0

def increment():
    # Переменные объявленные вне функции нельзя изменять внутри функции
    # Существуют модификаторы global или non local, но эти особенности не рекомендуется использовать
    result += 1

# Если вызвать функцию increment(), то она выпадет в ошибку:
# UnboundLocalError: local variable 'result' referenced before assignment
#
# increment()<jupyter_output><empty_output><jupyter_text>Аргументы по умолчанию<jupyter_code>def greeting(name='Vasya'):
    print('Hello, {}'.format(name))

greeting()        # Hello, Vasya
greeting('Petya') # Hello, Petya<jupyter_output>Hello, Vasya
Hello, Petya<jupyter_text>Однако, надо быть осторожным, если в качестве аргумента мы передаем изменяемое значение, например, список:<jupyter_code>def append_one(iterable=[]):
    iterable.append(1)
    return iterable

# Ожидаемый результат:
print( append_one([5]) ) # [5, 1]<jupyter_output>[5, 1]<jupyter_text>Однако, что же произойдет, если мы вызовем функцию несколько раз?<jupyter_code>print( append_one() ) # [1]
print( append_one() ) # [1, 1]
print( append_one() ) # [1, 1, 1]<jupyter_output>[1]
[1, 1]
[1, 1, 1]<jupyter_text>Почему так происходит? Вначале, как мы ожидали вернется список из одной единицы, потому что функция взяла дефолтное значение (пустой список) и вставила значение 1. Если функция вызывается второй раз, то в списке возвращается две единички, хотя мы ожидаем одну. Чтобы понять, почему так, можно посмотреть у функции атрибут `__defaults__`:<jupyter_code>print( append_one.__defaults__ )<jupyter_output>([1, 1, 1],)<jupyter_text>Оказывается, там уже содержаться эти самые 3 единички. Почему так происходит? При определении/инициализации функции определяются связи между именем функции и дефолтными значениями, т.о. у каждой функции появляется `tuple()` с дефолтными значениями-переменными и именно для этой переменной каждый раз вызывается метод `append()` в теле функции.Таким образом, дефолтные значения не инициализируются каждый раз при вызове функции.Что же нужно делать в таком случае? Как избежать этого?В объявлении функции нужно указать дефолтное значение как `None`, и если значение аргумента не передано,то создать его с помощью условия внутри функции:<jupyter_code>def append_one(iterable=None):
    if iterable is None:
        iterable = [] # Список создается в локальной области видимости функции, а не в атрибуте __defaults__
    iterable.append(1)
    return iterable   # Возвращаем из функции ссылку на созданный объект

print( append_one() ) # [1]
print( append_one() ) # [1]<jupyter_output>[1]
[1]<jupyter_text>Звездочки в аргументах. Распаковка аргументовФункция принимает разное количество аргументов:<jupyter_code>def printer(*args):
    print(type(args)) # <class 'tuple'>

    for arg in args:
        print(arg)

printer(1, 2, 3, 4, 5)<jupyter_output><class 'tuple'>
1
2
3
4
5<jupyter_text>Точно так же, мы можем разворачивать список в аргументы:<jupyter_code>name_list = ['John', 'Bill', 'Amy']
printer(*name_list) # Список распаковывается в аргументы<jupyter_output><class 'tuple'>
John
Bill
Amy<jupyter_text>Так же, это работает в случае со словарями:<jupyter_code>def printer(**kwargs):  # Происходит упаковка переданных аргументов в словарь kwargs
    print(type(kwargs)) # <class 'dict'>

    for k, v in kwargs.items():
        print('{}: {}'.format(k, v))

printer(a=10, b=11)<jupyter_output><class 'dict'>
a: 10
b: 11<jupyter_text>Возможно разворачивать словари в обратную сторону:<jupyter_code>payload = {
    'user_id': 117,
    'feedback': {
        'subject': 'Registration fields',
        'message': 'There is no country for old man'
    }
}

printer(**payload) # Распаковывается в последовательность аргументов user_id и feedback<jupyter_output><class 'dict'>
user_id: 117
feedback: {'subject': 'Registration fields', 'message': 'There is no country for old man'}
StarcoderdataJupyterStructuredCleanDedup