Лекция № 5. Вспомогательные алгоритмы. Объявление и вызов функций.

Хорошевич Павел Александрович

Функции

Определение функции

Функция – это именованный набор инструкций, которые могут быть выполнены в любом месте программы, после вызова функции.

Для объявление функции используется инструкция def.

def <имя функции>(<параметры>):
    <блок инструкций>

Строка с инструкцией def называется заголовком функции, а блок инструкций внутри функции называется телом функции.

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

Пример:

def hello():
    """Это функция приветствует пользователя"""
    print("Привет")
    print("Рад видеть вас")

Если запустить код выше, то мы не увидим сообщений на экране. Нужно разделять определение функции и её вызов.

Вызов функции

Чтобы вызвать функцию нужно записать её имя и в круглых скобках указать аргументы, если необходимо:

<имя функции>(<аргументы>)

Проследим за вызовом функции hello по шагам.

Параметры и аргументы

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

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

def hello2(name, rep):
    msg = " Привет, " + name
    print(msg * rep)

flowchart LR
    A[ ] -->|name| B["👋🏼<br/>hello2"]
    C[ ] -->|rep| B
    
    style B fill:#ffe0e6,stroke:#d6336c,stroke-width:2px,rx:15,ry:15,min-width:200px,min-height:100px
    style A fill:none,stroke:none
    style C fill:none,stroke:none

Рисунок 1

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

def hello2(name, rep):
    msg = " Привет, " + name
    print(msg * rep)
    
hello2("Света", 3)
hello2("Дима", 4)

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

Изменяемые объекты передаются по ссылке (списки) и могут быть изменены в теле функции.

def changer(n, s, l):
    n = n + 2
    s = s.upper()
    l[0] = "start"

x = 1
st = "hello"
lst = [1, 2, 3]

changer(x, st, lst)
print(x, st, lst)

Визуализация

Параметры и аргументы в Python могут сопоставляться несколькими способами.

По позиции: важен порядок в котором аргументы записаны при вызове функции.

def formatDate(day, month, year):
    """Выводим дату в красивом формате"""
    print(f"Сегодня {day}.{month} {year} года")

formatDate(22, 11, 2026) # аргументы в правильном порядке
formatDate(11, 2026, 22) # аргументы перепутаны

По имени: указываем имена параметров из заголовка функции.

def formatDate(day, month, year):
    print(f"Сегодня {day}.{month} {year} года")

# аргументы в произвольном порядке
formatDate(month=11, year=2026, day=22) 

Значения по умолчанию для параметров.

def formatDate(day, month, year=2026):
    print(f"Сегодня {day}.{month} {year} года")

formatDate(1, 9)
formatDate(1, 9, 1991)

Переменное количество аргументов:

def sum(*nums):
    s = 0
    for n in nums:
       s = s + n
    return s

sum(1, 2)
sum(5)
sum(5, 3, 6, 4, 3, 5, 1)

Визуализация

Возвращаем значение - return

Чтобы вернуть значение из функции используется инструкция return.

Пример: функция square(x), которая возводит число x в квадрат:

def square(x):
    y = x * x
    # возвращаем результат
    return y  

n = 10
result = square(n)
print("Результат:", result)

flowchart LR
    A[ ] -->|x| B["🟩<br/>square"]
    B -->|return| E[ ]
    
    style B fill:#ffe0e6,stroke:#d6336c,stroke-width:2px,rx:15,ry:15,min-width:200px,min-height:100px
    style A fill:none,stroke:none
    style E fill:none,stroke:none

Рисунок 2

Если в определении функции нет инструкции return то по окончании работы она всё равно вернёт специальное значение None:

def square(x):
    y = x * x
    # забыли написать return

print("Результат:", square(8))

После выполнения инструкции return функция прекращает свою работу.

Если какие-либо инструкции были записаны после return, они выполняться не будут:

def year():
    print("Функция запустилась")
    return 2026
    print("Это строка не выполнится")
    return 2007 # эта тоже

x = year()
print(x)

В описании функции может быть несколько инструкций return:

def year(val):
    if val == 2026:
        return "Текущий год"
    elif val < 2025:
        return "Прошлый год"
    else:
        return "Будущее"

x = year(1991)
print(x)

Область видимости переменных

Область видимости переменной определяется местом в котором ей было присвоено значение.

Существует две основные области видимости:

  • локальная: если присваивание значения переменной происходит внутри инструкции def то такая переменная будет локальной для этой функции;

  • глобальная: присваивание значение переменной происходит за пределами всех инструкций def.

Пример:

def square(x):
    y = x * x
    return y

r = square(10)
print(y)
  • глобальные имена: r и square;
  • локальные имена: x и y – присваивание значений обоим именам осуществляется внутри определения функции.

Визуализация

Функция - это объект

Каждая функция в Python - это объект на который может ссылаться несколько имён, их можно сделать элементами списка.

def summa(a, b):
    return a + b

s = summa # теперь на функцию ссылаются два имени - summa и s
print(summa(3, 2))
print(s(3, 2))

В следующем примере три функции помещаем в список и перебираем этот список с помощью цикла for:

def summa(a, b):
    return a + b
def mult(a, b):
    return a * b
def power(a, b):
    return a ** b

func_lst = [summa, mult, power] # список функций

x = 4
y = 3
for func in func_lst:
    # на каждой итерации func ссылается на очередную функцию
    value = func(x, y)
    print(value)

Визуализация

Вопрос? Вопрос. Вопрос!

  1. С какого служебного слова начинается описание функции?
  2. С помощью какой инструкции можно вернуть значение из функции?
  3. Объясните отличие глобальной и локальной областей видимости.
  4. Чем отличаются термины «параметр» и «аргумент».
  5. Какие типы данных передаются в функцию по ссылке?
  6. Назовите способы сопоставления параметров и аргументов.

Модули

Каждый файл с расширением .py является модулем, который можно использовать самостоятельно, или импортировать в другой модуль (файл с кодом).

graph LR
    subgraph Python-файлы
        A[main.py]
        B[mod1.py]
        C[mod2.py]
        A --> B
        A --> C
    end
    A --> D[Cтандартная библиотека]
    B --> D
    C --> D

Создание модуля

calc.py
def sum(x,y):
    return x + y

def average(x, y):
    return (x + y)/2

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

Переменные и функции внутри модуля называются атрибутами модуля.

Имя модуля должно следовать правилам именования переменных.

Импорт модуля

Инструкция import

main.py
import calc

s = calc.sum(2, 2)
avg = calc.average(5, 10)

print(s)
print(avg)

Инструкция from

main.py
from calc import sum, power
# from calc import *

sqr = power(2, 4)
print(sqr)

В данном примере файлы calc.py и main.py должны располагаться в одной папке

Инструкция import

Загружает модуль целиком, поэтому при обращении к именам в модуле их необходимо дополнять именем модуля:

модуль.атрибут

Инструкция from

Загружает (копирует) из модуля отдельные имена.

Из модуля можно загрузить в основной скрипт все атрибуты (*) либо только необходимые, перечислив их через запятую.

Установка сторонних пакетов

Пакетом называется набор модулей находящихся в одной папке.

Каталог пакетов расположен на сайте https://pypi.org/.

Для установки дополнительных пакетов используется консольная команда pip – Установщик пакетов для Python:

pip install <название пакета>
pip install requests

Модуль turtle

Чтобы использовать модуль рисования turtle, нужно его импортировать в программу:

from turtle import *

Работать с черепахой можно в процедурном или объектно-ориентированном стиле.

Процедурный стиль:

from turtle import *

forward(60)
left(45)
forward(60)

done()

Объектно-ориентированный:

from turtle import *
# создаём объект "Черепаха"
t = Turtle() 

t.forward(60)
t.left(45)
t.forward(60)

done()

Объектно-ориентированный подход полезен в том случае, когда для рисования используют две и больше черепашек:

from turtle import *
alice = Turtle()   # черепаха alice
bob   = Turtle()   # черепаха bob

# указываем для каждой черепахи
# свой набор действий
alice.forward(60)
alice.write("Я - alice")
bob.right(180)
bob.forward(60)
bob.write("Я - bob")

done()

Текущее расположение и направление черепах можно узнать с помощью следующих методов:

Таблица 1: Свойства черепахи
Свойство Процедурный стиль ООП стиль
Координата x Черепахи xcor() <черепаха>.xcor()
Координата y Черепахи ycor() <черепаха>.ycor()
Текущее направление Черепахи (в градусах) heading() <черепаха>.heading()

Движение черепахи

Таблица 2: Методы для перемещения черепах
Метод Назначение
forward(<пиксели>) Движение вперёд на указанное количество пикселей в сторону, куда направлена Черепаха
backward(<пиксели>) Движение назад на указанное количество пикселей
right(<градусы>) Поворот Черепахи направо на указанное количество градусов
left(<градусы>) Поворот Черепахи налево на указанное количество градусов
goto(x, y) Переместить Черепаху в точку с координатами (x, y).

Нарисуем многоугольник в следующем примере, используя методы forward() и left():

from turtle import *

speed(1)

n = 5
for i in range(n):
    forward(75)
    left(360 // n)

done()

Рисование

Во время движения, черепашка рисует свою траекторию движения. Для настройки пера используются следующие методы:

Таблица 3: Методы для настройки пера
Метод Назначение
pensize(<пиксели>) Изменяем толщину линии
penup() Поднимаем перо. С этого момента линия не рисуется
pendown() Опускаем перо. С этого момента линия рисуется
pencolor(<цвет>) Меняем цвет пера. Метод может принимать строковый аргумент <цвет> - название одного из встроенных цветов
from turtle import *

# список цветов
colors = ["green", "orange", "blue", "indigo", "teal"]

for i in range(40):
    # толщина линии зависит от итерации цикла
    pensize(i)
    # циклически меняем цвет линии: 0,1,2,3,4,0,1,2...
    pencolor(colors[i % 5])
    # с каждой итерацией увеличиваем длину стороны
    forward(i * 2)
    left(35)

done()

Очерченный черепахой контур можно залить выбранным цветом.

Таблица 4: Методы для управления заливкой
Метод Назначение
fillcolor(<цвет>) Выбираем цвет заливки
begin_fill() Обозначаем начало контура
end_fill() Обозначаем конец контура. Если контур не замкнут, то две крайние точки соединяться отрезком
from turtle import *

speed(1)
fillcolor("blue")
begin_fill() # начало заливки

n = 5
for i in range(n):
    forward(75)
    left(360 // n)

end_fill() # конец заливки
done()