function основное.md 10 KB

~={green}Определения:=~

  • Функция - именованный блок кода который выполняет определенную задачу или возвращает значение.
  • Функция - набор операторов, которые возвращают некоторое значение вызывающему объекту. В функцию также может быть передано ноль или более аргументов, которые могут использоваться при выполнении тела функции.
  • Такое определение функций допустимо, но вторая функция перезатрет первую.

    def f():
        print("QWERTY")
    
    def f():
        print("ABC")
    
    f()
    f()
    
  • Любая функция в python возвращает значение. Значение возвращается при помощи оператора return. Если функция не содержит оператор return, то по умолчанию такая функция вернет значение None.

  • Функция должна выполнять только одну операцию. Она должна выполнять ее хорошо. И ничего другого она делать не должна. Если функция выполняет только те действия, которые находятся на одном уровне под объявленным именем функции, то эта функция выполняет одну операцию.

  • Будьте последовательны в выражениях возврата: либо все операторы return в функции должны возвращать выражение, либо ни один из них не должен. Если какой-либо оператор return возвращает выражение, то оставшиеся операторы return тоже должны явно возвращать значение, не смотря на то, что python по умолчанию возвращает None. Статья по оформлению [[https://pythonchik.ru/osnovy/imenovanie-v-python]]

~={green}Пример оформления простой функции:=~

# is - в названии функциии
# нет лишних return
def is_even(x):
    return x%2 == 0

# пример использования без лишних сравнений
number = int(input("Введите число: "))
while is_even(number):
	print(f'{number} является четным')
	number = int(input("Введите число: "))
print(f"Вы ввели нечетное число {number}, программа завершилась")

~={green}Возврат кортежа=~

# в return можно не ставить скобки, все равно будет возвращен кортеж
def calc_square_and_perimeter(a, b):
	retun a * b, 2 * (a + b)

~={green}Возврат списка=~

# в данном случае нужны скобки [ ]
def calc_square_and_perimeter(a, b):
	return [a * b, 2 * (a + b)]

~={green}Передача аргументов=~

  • При комбинированной передачи аргументов сначала должны быть указаны позиционные аргументы, а только потом именованные!
  • Параметры являются локальными переменными и они определяются в момент вызова функции. В параметры присваиваются ссылки на объекты, переданные в аргументы.
  • Параметры функции делятся на _обязательные_ и _необязательные_.
  • Никогда не используйте изменяемые объекты в качестве значений по умолчанию.
  • Значение по умолчанию вычисляется только один раз при определении функции.

~={green}Изменяемые объекты в качестве параметров по умолчанию=~

  • сперва присваивайте параметру значению None
  • внутри функции проверяйте, если параметр принимает None, значит создаем пустой изменяемый объект

    def append_to_list_2(value, my_list=None):
        if my_list is None:
            my_list = []
        my_list.append(value)
      print(my_list, id(my_list))
        return my_list
    

~={green}Множественное присваивание=~ Остальные значения сохраняются в виде списка с переменную "с"

a, b, *c = [1, True, 4, 6, 'hello ', 7, 9]
1, True, [4, 6, 'hello ', 7, 9]

a, *b, c = [1, True, 4, 6, 'hello ', 7, 9]
1, [True, 4, 6, 'hello ', 7], 9

a, b, *c = [1, True, 4, 6, 'hello ', 7, 9]
1, True, [4, 6, 'hello ', 7, 9]

a, *b, c = 'hello moto'
h ['e', 'l', 'l', 'o', ' ', 'm', 'o', 't'] o

a, *b, c = [1, 4]
1 [] 4

~={green}Передача переменного количество аргументов=~

def my_func(*args)
def my_func(**kargs)

# Необязательный аргумент после *args
def my_func(*args, foo=True)

# Объединенный вариант передачи аргументов
def my_func(a, b, *args, c, d=4, **kwargs):

В args будет ~={red}кортеж=~. В kwargs будет ~={red}словарь=~.

# При распаковке словаря передаются значения
def print_args(a, b, c=15):
    print(a, b, c)

dct = {'a': 5, 'b': 10}
print_args(**dct)

>>> 5, 10 15

# Распаковка при передачи списка и словаря
my_list =[5, 19, 23, 88]
my_dict = {'a': 11, 'b': 23}
item_sum(*my_list, **my_dict)

~={green}Как нельзя передавать аргументы=~ ~={red}Нельзя передавать позиционные аргументы после именованных!=~

def my_func(a, b, *args):
    print(f'{a=}, {b=}, {args=}')

# Будет ошибка при передаче аргументов по ключам
my_func(a=20, b=20, 30, 40, 50)

~={green}Только ключевые аргументы=~ Все параметры, которые стоят справа от * должны принимать значения только по ключу. Все параметры, которые стоят слева от / должны принимать значения только по позиции. * - только ~={magenta}ключевые=~ аргументы / - как ~={magenta}позиционные=~ так и ~={magenta}ключевые=~ аргументы

def my_func(*, a, b):
    print(f'{a=}, {b=}')

# Так передать можно
my_func(b=30, a=40)

# А так нельзя
my_func(10, b=20)

~={green}Объект первого класса=~

  • С ним можно работать как с переменными
  • Он может быть передан в функцию как аргумент
  • Он может быть возвращен из функции как результат
  • Он может быть включен в другие структуры данных. Например, быть элементом словаря или списка

~={green}Пространство имен=~

Встроенное пространство имен (build-in namespace) представляет собой набор имен всех встроенных функций и объектов в Python. 

# Выведет все объекты встроенного пространства имен
print(dir(__builtins__))

Глобальное пространство имен (global namespace) содержит имена, определенные на уровне основной программы, и создаётся сразу при запуске тела этой программы.

Локальное пространство имен (local namespace) содержит имена, которые доступны только внутри определенной функции.

Локальная область создается при вызове функций, причем каждый раз, когда вы вызываете функцию, будет создаваться новая локальная область видимости. Все параметры и имена, которые вы создаете внутри функции, образуют локальную область этой функции в пределах одного конкретного вызова. Когда функция завершает работу, локальная область видимости уничтожается, а имена забываются

# Вывести локальное пространство имен
print(locals())

Объемлющее пространство имен возникает когда определение одной функции вкладывается в другую.

def main_func():
    a = 1

    def inner_func():
        print('Печатаем a из inner_func', a)
        print('Печатаем b из inner_func', b) # Вот тут будет ошибка NameError

    inner_func()
    b = 2
    print('Печатаем a из main_func', a)
    print('Печатаем b из main_func', b)


main_func()

Для изменения переменной a в inner нужно использовать nonlocal.

~={green}Создание атрибутов функциям =~

def get_product(a: int, b: int) -> int:
    return a + b

get_product.category = 'math'
get_product.type_action = 'arithmetic operation'

# Или через setattr
setattr(obj, name_attr, value)


~={green}Вложенные функции (inner function)=~ Вложенные функции имеют доступ к параметрам и к переменным, определенным во внешней функции. Применяются в замыканиях. Определяются в момент вызова родительской функции.