Skip to content

Latest commit

 

History

History
498 lines (369 loc) · 23.6 KB

README.md

File metadata and controls

498 lines (369 loc) · 23.6 KB
  • Расширенное использование функций - «первоклассные граждане» / функции высшего порядка / лямбда-функции / области видимости и замыкания / декораторы

Расширенное использование функций (день 17)

В Python функции могут быть использованы для решения широкого спектра задач и проблем. Вот несколько расширенных сценариев использования функций:

  1. Рекурсивные функции - функции, которые вызывают сами себя. Это особенно полезно в алгоритмах, которые подразумевают глубокую вложенность.

  2. Функции высшего порядка - это функции, которые принимают другие функции в качестве аргументов или возвращают их как результат. Это особенно полезно для функционального программирования.

  3. Анонимные функции (лямбда-выражения) - это функции без имени, которые могут использоваться в качестве аргументов в других функциях для создания кратких и компактных выражений.

  4. Генераторы - это функции, которые используются для создания итераторов в Python. Они позволяют создавать последовательности значений по требованию, вместо того, чтобы создавать целую последовательность сразу.

  5. Декораторы - это функции, которые позволяют изменять поведение других функций. Декораторы могут использоваться для добавления дополнительной функциональности функциям без изменения их кода.

  6. Модуль functools - это стандартный модуль Python, который содержит множество функций, которые могут использоваться для дополнительной обработки и изменения поведения функций в Python. Здесь можно найти функции, такие как functools.partial, которые позволяют создавать новые функции на основе существующих, и functools. lru_cache, который позволяет кэшировать результаты выполнения функции для повышения ее производительности.

Функция как "гражданин первого класса"

Python - объектно-ориентированный язык программирования, в котором функции - это "граждане первого класса". Это означает, что функции в Python имеют множество свойств классических объектов, таких как возможность передачи как параметров, возвращение в качестве результата, сохранение в переменных и передача другим функциям.

Это является очень мощным инструментом, позволяющим создавать сложные программы и сокращать объем кода благодаря возможности переиспользования кода внутри программы.

Ниже приведены некоторые примеры использования функций в Python:

  1. Простая функция для вычисления квадрата числа:
def square(x):
    return x*x

result = square(5)
print(result) # Выведет 25
  1. Функция, принимающая список чисел и возвращающая сумму всех чисел в списке:
def sum_numbers(numbers):
    sum = 0
    for num in numbers:
        sum += num
    return sum
    
result = sum_numbers([1, 2, 3, 4, 5])
print(result) # Выведет 15
  1. Функция, использующая функцию в качестве параметра:
"""
Python 3.10 расширенные возможности функции
Название файла '01.калькулятор.py'

Version: 0.1
Author: Andrej Marinchenko
Date: 2023-05-03
"""

def calculator(operation, x, y):
    if operation == "add":
        return x+y
    elif operation == "subtract":
        return x-y
    elif operation == "multiply":
        return x*y
    elif operation == "divide":
        return x/y

def square(x):
    return x*x

result = calculator("multiply", 5, 6)
print(result)  # Выведет 30 = 5*6
print(square(5))  # Выведет 25 = 5*5
print(calculator(square, 5, 5))  # None
print(calculator("divide", square(10), 5))  # 20.0 =((10*10)/5)

Функция «калькулятор» принимает одну из четырех операций и два числа в качестве параметров. Затем она использует переданную функцию в качестве операции и выполняет операцию между двумя числами.

  1. Анонимные функции:
square = lambda x: x*x

result = square(5)
print(result) # Выведет 25

Анонимная функция - это функция без имени, которая может быть определена в одну строку кода. Они удобны, когда вам нужна небольшая функция, которую можно определить прямо на месте. В приведенном примере мы определяем функцию square, которая возвращает квадрат переданного числа.

В целом, использование функций как "граждан первого класса" в Python позволяет создавать более читабельный и переиспользуемый код. Их можно использовать для многих задач, таких как вычисление, обработка данных и многих других.

Высшие функции в Python

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

Приведу несколько примеров высших функций в Python с описанием:

  1. map(function, iterable) - применяет функцию к каждому элементу итерируемого объекта (например, списка или кортежа) и возвращает новый итератор с результатами. Пример:
def square(x):
    return x ** 2

numbers = [1, 2, 3, 4, 5]
squared_numbers = list(map(square, numbers))
print(squared_numbers) # Output: [1, 4, 9, 16, 25]
  1. filter(function, iterable) - возвращает новый итератор с элементами итерируемого объекта, для которых функция возвращает истинное значение. Пример:
# функция определения не четных чисел
def is_odd(x):
    return x % 2 != 0  # возвращает число не кратное двум

numbers = [1, 2, 3, 4, 5]
odd_numbers = list(filter(is_odd, numbers))
print(odd_numbers)  # Output: [1, 3, 5]
  1. reduce(function, iterable[, initializer]) - применяет функцию к элементам итерируемого объекта, частично сводя его к одному значению. Пример:
from functools import reduce

def multiply(x, y):
    return x * y

numbers = [1, 2, 3, 4, 5]
product = reduce(multiply, numbers)
print(product) # Output: 120
  1. lambda arguments: expression - используется для создания анонимных функций. Пример:
square = lambda x: x ** 2
print(square(5)) # Output: 25
  1. sorted(iterable, key=None, reverse=False) - сортирует элементы итерируемого объекта в порядке возрастания (или убывания, если reverse=True) и возвращает новый отсортированный список. Ключ key определяет функцию, которая будет использоваться для извлечения значения, по которому будет происходить сортировка. Пример:
names = ['Alice', 'Bob', 'Charlie', 'Dave']
sorted_names = sorted(names, key=len)  # отсортирует список по длине каждого слова
print(sorted_names) # Output: ['Bob', 'Dave', 'Alice', 'Charlie']

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

Лямбда-функции

Лямбда-функции в Python - это анонимные функции, которые могут быть определены в одной строке. Они могут быть использованы везде, где требуется функция, но не требуется назначать ее имени. Вот несколько примеров лямбда-функций в Python:

'''Пример 1:'''
lambda x: x**2 
# Эта лямбда-функция берет один аргумент x и возвращает квадрат этого аргумента.

'''Пример 2:'''
lambda x, y: x + y 
# Эта лямбда-функция берет два аргумента, x и y, и возвращает их сумму.

'''Пример 3:'''
lambda x: True if x >= 0 else False 
# Эта лямбда-функция берет один аргумент x и возвращает True, если x больше или равен нулю, и False в обратном случае.

'''Пример 4:'''
lambda x: x[0] 
# Эта лямбда-функция берет один аргумент x, который является списком или кортежем, и возвращает первый элемент этого списка.

'''Пример 5:'''
(lambda x: x**2)(3) 
# Этот пример показывает, как вызвать лямбда-функцию с аргументом. Здесь мы вызываем функцию, которая берет один 
# аргумент x и возвращает его квадрат, передавая в нее значение 3. Результатом выполнения будет число 9. 

Это только несколько из возможных примеров использования лямбда-функций в Python. Они могут быть использованы в любом контексте, где необходима быстрая, одноразовая функция.

Области видимости и замыкания функций

Область видимости определяет область, в которой переменная доступна и может быть использована. В Python есть две основные области видимости: глобальная и локальная.

Локальная область видимости ограничена функцией, в которой переменная была определена. Переменные, созданные внутри функции, не могут быть использованы за ее пределами.

Пример:

def my_function():
    x = 10
    print(x)

my_function()  # результат: 10
print(x)  # ошибка, переменная x не определена в глобальной области видимости

Глобальная область видимости доступна для всего кода, который находится в файле. Переменные, созданные в глобальной области видимости, могут быть использованы в любой другой функции или классе.

Пример:

x = 20

def my_function():
    print(x)

my_function()  # результат: 20
print(x)  # результат: 20

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

Пример:

def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

result = outer_function(10)
print(result(20))  # результат: 30

Этот пример создает функцию outer_function, которая возвращает другую функцию inner_function. При вызове outer_function(10) в переменной result сохраняется результат inner_function. Поэтому result(20) вызывает inner_function(20) с результатом 30. Хотя x была определена в outer_function, она все еще доступна для использования внутри inner_function благодаря замыканию функций.

Декораторы

Декораторы функций - это специальные функции, которые используются для обертки или изменения других функций без необходимости изменения их самостоятельно. Они позволяют добавлять дополнительную функциональность к функциям, не затрагивая ее исходного кода.

Примеры декораторов функций:

  1. @classmethod - это декоратор класса, который используется для создания методов класса.

Пример:

class MyClass:
    count = 0

    def __init__(self):
        MyClass.count += 1

    @classmethod
    def get_count(cls):
        return cls.count
  1. @property - это декоратор, который позволяет превратить метод класса в свойство.

Пример:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError("Radius cannot be negative")
        self._radius = value

    @property
    def area(self):
        return 3.14 * self._radius ** 2
  1. @staticmethod - это декоратор, который объявляет метод класса как статический.

Пример:

class MyClass:
    @staticmethod
    def get_square(number):
        return number ** 2

В этом примере мы объявляем метод get_square() статическим, чтобы использовать его без необходимости создания экземпляра класса.

  1. @log - это декоратор, который добавляет логирование в функцию.

Пример:

import logging

logging.basicConfig(filename='logfile.txt',level=logging.DEBUG)

def log(func):
    def wrapper(*args, **kwargs):
        logging.debug(f"Executing function {func.__name__}")
        result = func(*args, **kwargs)
        logging.debug(f"Function {func.__name__} returned {result}")
        return result
    return wrapper

@log
def add(x, y):
    return x + y

В этом примере мы создаем декоратор log(), который добавляет логирование для функции add(), чтобы мы могли отслеживать ее выполнение.

пример: декоратор времени выполнения выходной функции.

def record_time(func):
    """Декоратор для индивидуально оформленных функций"""
    
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time()
        result = func(*args, **kwargs)
        print(f'{func.__name__}: {time() - start}秒')
        return result
        
    return wrapper

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

Декоратор в Python - это функция, которая принимает в качестве аргументов другую функцию, выполняет некоторые действия и возвращает эту функцию. Параметризуемые декораторы в Python - это декораторы, которые могут принимать аргументы. Вот несколько примеров параметризуемых декораторов:

  1. Декоратор, который выполняет функцию указанное количество раз:
def repeat(num):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(num):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(num=3)
def hello(name):
    print(f"Hello, {name}")

hello("Jack")  # Hello, Jack
               # Hello, Jack
               # Hello, Jack
  1. Декоратор, который замеряет время выполнения функции:
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        total_time = end_time - start_time
        print(f"Execution time: {total_time}")
        return result
    return wrapper

@timer
def count():
    num = 0
    for i in range(1000000):
        num += i
    return num

count()  # Execution time: 0.07399797439575195
         # 499999500000
  1. Декоратор, который выполняет функцию только если ее аргументы удовлетворяют условие:
def check_args(type):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for arg in args:
                if type(arg) != type:
                    return f"Invalid argument type: {arg}"
            for key, value in kwargs.items():
                if type(value) != type:
                    return f"Invalid argument type: {key}"
            return func(*args, **kwargs)
        return wrapper
    return decorator

@check_args(int)
def sum(x, y):
    return x + y

print(sum(1, 2))        # 3
print(sum("a", "b"))    # Invalid argument type: a
print(sum(1, "b"))      # Invalid argument type: b

Эти примеры помогут вам понять, как можно использовать параметризуемые декораторы в Python.

Рекурсивная функция

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

Пример 1:

Функция, которая вычисляет факториал числа. Факториал числа n обозначается через n! и равен произведению всех натуральных чисел от 1 до n включительно:

def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)

В этой функции сначала проверяется, не является ли n равным 1. Если это так, то возвращается 1 (факториал числа 1 равен 1). Если же n не равно 1, то функция возвращает произведение числа n на результат вызова функции с аргументом n-1. Таким образом, функция вызывает саму себя, пока не достигнет базового случая (n=1).

Пример 2:

Функция, которая вычисляет числа Фибоначчи. Числа Фибоначчи определяются следующей последовательностью: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ... Каждый следующий элемент равен сумме двух предыдущих элементов.

def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)

В этой функции сначала проверяется, не является ли n равным 0 или 1. Если это так, то возвращается соответствующий элемент последовательности. Если же n больше 1, то функция возвращает сумму результатов вызовов функции с аргументами n-1 и n-2. Таким образом, функция вызывает саму себя, пока не достигнет базовых случаев (n=0 или n=1).

Примеры:

  • 01.калькулятор.py
  • 02.рекурсивная_функция.py
  • 03.область_действия.py

Вернуться на главную

К следующему занятию