Проект для лекции Lecture6.rar.
Язык Python поддерживает разные стили программирования. Все они предназначены для борьбы со сложностью программных проектов. Функциональное программирование работает на уровне метода, позволяя в результате декомпозиции представить метод в виде композиции более простых методов. Модульное программирование работает на более высоком уровне, когда проект разрабатывается, не как единый модуль, а представляется в результате декомпозиции в виде композиции более простых модулей. Например, если проект предназначен для моделирования работы некоторого предприятия, то в проекте могут появиться такие модули, как "Финансы", "Производство", "Склад", "Логистика". При необходимости каждый из этих модулей может быть декомпозирован на более простые модули.
Содержательно, каждый модуль включает набор сервисов, решающих определенные задачи в своей проблемной области. Благодаря возможностям импорта - экспорта сервисов модули могут взаимодействовать, предоставляя свои сервисы другим модулям.
Функциональное и модульное программирование неразрывно связаны друг с другом. Вы не можете создать функцию Python , не создав предварительно модуль. Модуль является контейнером, в который помещаются функции. С другой стороны, модуль, во многом это набор функций, или, пользуясь более общим термином, набор методов, каждый из которых представляет сервис, поставляемый модулем своим клиентам. Во многих случаях модуль ничего не содержит кроме методов. Когда мы разрабатываем отдельный модуль, то мы занимаемся функциональным программированием - программированием в функциях, как это было описано в предыдущей лекции. Но когда мы переходим на более высокий уровень проектирования большого программного проекта, то нам приходится заниматься программированием в модулях, выполняя декомпозицию большой системы на совокупность взаимодействующих модулей.
Любая программа на Python содержит хотя бы один модуль. Давайте вспомним примеры программ, приводимых в прошлых лекциях, и посмотрим, как устроены модули в этих примерах. В лекции, посвященной стилям программирования, рассматривались простейшие программы, представляющие выполняемую последовательность операторов языка Python . Как создать проект такого типа? Достаточно в любом текстовом редакторе открыть файл, записать в него программу на Python , состоящую из последовательности операторов, сохранить файл с уточнением .py. В результате будет создан модуль, который может быть выполнен интерпретатором Python .
Справедливы следующие утверждения:
В лекции по функциональному стилю программирования и в ранее появляющихся примерах модули устроены более сложно.
Справедливо следующее утверждение:
Заметьте, определение - это определение, а не выполняемый код. Чтобы выполнить метод, он должен быть вызван.
В наших примерах рассматривались простые задачи, для решения которых создавался метод. Заметьте, хотя явно это не акцентировалось, но применялся поход, характерный для модульного и функционального стиля программирования, когда интерфейс задачи отделяется от сути задачи (часто говорят "от бизнес-логики задачи"). Поэтому уже на начальном этапе выполнялась декомпозиция задачи, в результате которой создавались два метода.
Один метод, у которого формальными аргументами были входные данные, решал задачу по существу. Этот метод и задает сервис модуля.
Другой метод отвечал за интерфейс с пользователем. Он получал значения входных данных от пользователя или из файла, вызывал бизнес-метод, передавая ему входные данные, получал результат и выводил результаты в виде, необходимом пользователю. Для одной и той же задачи интерфейсы могут быть разными, ориентированными на разных пользователей.
В наших примерах создавался бизнес-метод X и соответствующий ему интерфейсный метод - процедура с именем testX. Программа main модуля вызывала метод testX, который в свою очередь вызывал соответствующий сервис - бизнес метод X.
Модуль может быть устроен более сложно, - иметь не только методы, но и атрибуты. Сегодняшняя лекция будет посвящена более полному описанию структуры модуля. Но, вначале, продолжая тему функционального программирования, хочу остановиться на некоторых аспектах построения методов.
В классическом функциональном программировании информация в функцию передается через параметры функции, а результаты, вычисленные функцией, представлены значением, возвращаемым функцией. Поскольку в роли возвращаемого значения может быть список, содержащий объекты разных типов, то нет ограничений на число результатов, вычисляемых функцией, и их типы. Формально, и функции могли бы иметь один параметр - список, в котором функции передавалась бы вся необходимая ей информация. Возможность упаковки множества параметров в список - хороший прием, но он усложняет понимание того, что делает метод. Поскольку параметры имеют разный смысл и могут быть разных типов, то удобнее, конечно, иметь множество параметров. Возможность иметь параметры, значения которых задаются по умолчанию, иметь параметр, которому ставится в соответствие кортеж фактических параметров, существенно облегчает разработку.
В практическом программировании в отличие от классики применяются разные способы передачи информации в функцию и возвращения результатов работы функции. Мы уже видели на примере метода сортировки списка, что метод может быть интересен не возвращаемым результатом, а побочным эффектом. В этом случае метод является процедурой, - в его теле отсутствует оператор return и вызывается он как процедура. Входной параметр, представляющий ссылку на список, остается неизменным, а сам объект список изменяется. Такой способ передачи информации из функции широко применяется на практике.
В лекции по функциональному программированию мы определили функцию высшего порядка Integral, вычисляющую значение определенного интеграла, которой в качестве формального параметра передавалась подынтегральная функция. Тогда мы упростили задачу, полагая, что подынтегральная функция зависит только от одного аргумента. На практике подынтегральная функция может зависеть от многих параметров. Например, используемая нами функция f(x) = 2x + 1 является частным случаем линейной функции ax + b, для вычисления значений которой в общем случае требуется знать не только аргумент x, но и значения параметров a и b. Рассматриваемая там же функция g(x) является частным случаем квадратичной функции, у которой помимо x есть еще три параметра. Функция F(x) = f(g(x)), представляющая суперпозицию функций, также имеет три параметра - аргумент x и два параметра, задающие функции, участвующие в
суперпозиции. Как передать эту информацию функции высшего порядка Integral, учитывая, что разным подынтегральным функциям требуется разнородная информация. Рассмотрим способы решения этой задачи.
Начнем с классического варианта, когда для передачи информации используются входные параметры. Будем полагать, что подынтегральная функция - это функция от двух параметров. Первый параметр - это параметр x, - точка, в которой вычисляется функция. А второй параметр params - это список, содержащий всю необходимую дополнительную информацию. Это изменение в малой степени коснется функции Integral, - параметр params появится в списке формальных параметров и будет передаваться подынтегральной функции при ее вызове.
def Integral_M(a: float, b: float, f, params: list, eps: float)-> float:
"""
Вычисление определенного интеграла на интервале [a, b]
с подынтегральной функцией f(x, params).
Интеграл вычисляется как площадь.
eps - точность вычислений
"""
n = 1; d = b - a; s0 = -1; h = d/2
sf = (math.fabs(f(a, params)) + math.fabs(f(b, params)))/2
s1 = sf * d
while math.fabs(s1 - s0) > eps:
for i in range(n):
sf += math.fabs(f(a + h + 2 * i * h, params))
s0 = s1; s1 = sf * h; n = 2 * n; h = h /2
return s1
Это небольшое изменение существенно расширило возможности функции Integral, позволяя вычислять интеграл для более широкого класса подынтегральных функций. Вот несколько примеров вызова обновленной функции Integral_M. Подынтегральные функции во всех примерах задаются с помощью лямбда определений:
import math
def f(x: float)-> float:
return 2 * x + 1
def g(y: float)-> float:
return y * y + 4 * y - 5
def F (x: (int, float), f, g)-> float:
"""
Функция как объект. F- Функция высших порядков - аргументы f, g являются функциями
"""
return f(g(x))
def test1():
"""
Вызовы обновленной функции Integral_M
Подынтегральные функции задаются с использованием лямбда определений
"""
eps = 1e-7
pars = [2, 1]
mix = Integral_M(0, 2, lambda x, pars: pars[0] * x + pars[1], pars, eps )
print(mix)
pars = [1, 4, -5]
mix = Integral_M(0, 2, lambda x, pars: pars[0] *x *x + pars[1] * x + pars[2], pars, eps)
print(mix)
pars = [f, g]
mix = Integral_M(0, 2, lambda x, pars: pars[0](pars[1](x)), pars, eps)
print(mix)
test1()
Вот результаты работы:
Начнем с определения глобальных и локальных имен. Имена формальных параметров метода и все имена, определенные в теле метода, являются локальными именами метода. Область их видимости - тело метода. Вне метода эти имена не видимы. Время жизни локальных имен начинается с момента определения в теле метода и заканчивается в момент завершения выполнения метода. Локальные переменные существуют только тогда, когда метод вызывается на выполнение и исчезают, когда метод завершает работу. "Мавр сделал свое дело, мавр должен уйти"! Напомню, когда имени в теле метода присваивается значение, то это имя считается локальной переменной метода, имя связывается с объектом, забывая о том значении, которое оно могло иметь до выполнения присваивания.
Имя метода в отличие от имен формальных параметров является глобальным, - оно определено на уровне модуля и область его видимости - это весь модуль. Ранее мы не акцентировали на этом внимание, считая по умолчанию, что в теле метода можно вызывать любой метод, определенный в модуле. Это возможно только потому, имена методов модуля - это глобальные имена, видимые во всем модуле, и время их жизни совпадает со временем жизни модуля.
Глобальными являются не только имена методов, но и имена переменных, определенные на уровне модуля в программном коде, включенном в модуль.
Глобальные переменные модуля называются атрибутами модуля. Их значения определяют текущее состояние модуля. Атрибуты модуля также как и имена методов доступны во всем модуле, в том числе в теле любого метода. Это позволяет ввести еще один важный способ обмена информацией между модулем и методом модуля. Метод может использовать глобальные переменные для получения необходимой ему информации. Метод может не иметь параметров, получая всю необходимую информацию через глобальные переменные. Эта концепция модуля языка Python во многом схожа с концепцией ООП. В объектно-ориентированном программировании переменные, объявленные на уровне класса, являются полями класса, доступными для всех методов класса. Поля класса служат двум целям:
В языке Python переменные, введенные на уровне модуля, также можно рассматривать как поля или атрибуты модуля и полагать, что они играют ту же роль, что и поля класса в ООП.
Приведу пример использования глобальных переменных для передачи информации в функцию. Приведу еще одну модификацию функции высшего порядка Integral. Ранее в модификации этой функции Integral_M мы добавили формальный параметр, который передавался подынтегральной функции. Сейчас же в модификации Integral_S оставим только один параметр - имя подынтегральной функции, передавая всю остальную информацию через атрибуты модуля - глобальные переменные. Приведу вначале текст функции Integral_S:
def Integral_S(f)-> float:
"""
Вычисление определенного интеграла на интервале [a, b]
Интеграл вычисляется как площадь.
eps - точность вычислений
"""
n = 1; d = b - a; s0 = -1; h = d/2
sf = (math.fabs(f(a)) + math.fabs(f(b)))/2
s1 = sf * d
while math.fabs(s1 - s0) > eps:
for i in range(n):
sf += math.fabs(f(a + h + 2 * i * h))
s0 = s1; s1 = sf * h; n = 2 * n; h = h /2
return s1
В этой модификации мы снова вернулись к варианту, когда подынтегральная функция рассматривается как функция от одного аргумента. Всю остальную информацию она получает через глобальные переменные модуля. Приведу описание атрибутов модуля:
# Объявления переменных на уровне модуля a = 0 b = 2 A = 1 B = 4 C = -5 eps = 1e-7
Вот пример функции, которая при вычислении значения использует глобальную информацию:
def fun(x):
return A * x * x + B * x + C
Построим теперь интерфейсный метод, тестирующий работу функции Integral_S:
def test2():
"""
Обмен информацией через глобальные переменные
"""
mix = Integral_S(lambda x: A * x * x + B * x + C)
print("Функция, использующая глобальные переменные:", mix)
mix = Integral_S(fun)
print("Функция, использующая глобальные переменные:", mix)
test2()
Вот результаты выполнения:
Мы рассмотрели два крайних случая. В одном случае вся входная информация методу передается через механизм формальных - фактических параметров, в другом - большая часть входных данных передается через механизм атрибутов модуля - механизм глобальных переменных. Какой из этих способов предпочтительнее. Однозначного ответа нет. Недостатком классического функционального программирования, когда вся информация передается через формальные параметры, является появление большого числа параметров у функций. Представьте функция F - функция высшего порядка с функциональными аргументами f, g. Тогда вся входная информация, необходимая этим функциям, должна быть передана функции F, как это было с параметром params у функции Integral_M. В языке Python этот недостаток нивелируется тем, что при вызове передаются только ссылки, а не сами тяжелые объекты. Кроме того, есть приятная возможность при вызове задавать не все параметры, используя концепцию параметров по умолчанию.
В рассматриваемом нами случае разумным компромиссом было бы включить параметры a, b, eps в число формальных параметров метода Integral_B, задав их как параметры по умолчанию. Что же касается параметра params, то лучше предоставить решение пользователю, создав две модификации метода Integral с такими, например, заголовками:
def Integral_B1(f, a = 0, b = 1, eps = 1e-7 ):
pass
def Integral_B2(f, params, a = 0, b = 1, eps = 1e-7 ):
pass
Здесь тело метода представлено заглушкой pass, представляющей пустой оператор языка Python , который не выполняет никаких действий.
Проект для лекции Lecture6.rar.
Язык Python поддерживает разные стили программирования. Все они предназначены для борьбы со сложностью программных проектов. Функциональное программирование работает на уровне метода, позволяя в результате декомпозиции представить метод в виде композиции более простых методов. Модульное программирование работает на более высоком уровне, когда проект разрабатывается, не как единый модуль, а представляется в результате декомпозиции в виде композиции более простых модулей. Например, если проект предназначен для моделирования работы некоторого предприятия, то в проекте могут появиться такие модули, как "Финансы", "Производство", "Склад", "Логистика". При необходимости каждый из этих модулей может быть декомпозирован на более простые модули.
Содержательно, каждый модуль включает набор сервисов, решающих определенные задачи в своей проблемной области. Благодаря возможностям импорта - экспорта сервисов модули могут взаимодействовать, предоставляя свои сервисы другим модулям.
Функциональное и модульное программирование неразрывно связаны друг с другом. Вы не можете создать функцию Python , не создав предварительно модуль. Модуль является контейнером, в который помещаются функции. С другой стороны, модуль, во многом это набор функций, или, пользуясь более общим термином, набор методов, каждый из которых представляет сервис, поставляемый модулем своим клиентам. Во многих случаях модуль ничего не содержит кроме методов. Когда мы разрабатываем отдельный модуль, то мы занимаемся функциональным программированием - программированием в функциях, как это было описано в предыдущей лекции. Но когда мы переходим на более высокий уровень проектирования большого программного проекта, то нам приходится заниматься программированием в модулях, выполняя декомпозицию большой системы на совокупность взаимодействующих модулей.
Любая программа на Python содержит хотя бы один модуль. Давайте вспомним примеры программ, приводимых в прошлых лекциях, и посмотрим, как устроены модули в этих примерах. В лекции, посвященной стилям программирования, рассматривались простейшие программы, представляющие выполняемую последовательность операторов языка Python . Как создать проект такого типа? Достаточно в любом текстовом редакторе открыть файл, записать в него программу на Python , состоящую из последовательности операторов, сохранить файл с уточнением .py. В результате будет создан модуль, который может быть выполнен интерпретатором Python .
Справедливы следующие утверждения:
В лекции по функциональному стилю программирования и в ранее появляющихся примерах модули устроены более сложно.
Справедливо следующее утверждение:
Заметьте, определение - это определение, а не выполняемый код. Чтобы выполнить метод, он должен быть вызван.
В наших примерах рассматривались простые задачи, для решения которых создавался метод. Заметьте, хотя явно это не акцентировалось, но применялся поход, характерный для модульного и функционального стиля программирования, когда интерфейс задачи отделяется от сути задачи (часто говорят "от бизнес-логики задачи"). Поэтому уже на начальном этапе выполнялась декомпозиция задачи, в результате которой создавались два метода.
Один метод, у которого формальными аргументами были входные данные, решал задачу по существу. Этот метод и задает сервис модуля.
Другой метод отвечал за интерфейс с пользователем. Он получал значения входных данных от пользователя или из файла, вызывал бизнес-метод, передавая ему входные данные, получал результат и выводил результаты в виде, необходимом пользователю. Для одной и той же задачи интерфейсы могут быть разными, ориентированными на разных пользователей.
В наших примерах создавался бизнес-метод X и соответствующий ему интерфейсный метод - процедура с именем testX. Программа main модуля вызывала метод testX, который в свою очередь вызывал соответствующий сервис - бизнес метод X.
Модуль может быть устроен более сложно, - иметь не только методы, но и атрибуты. Сегодняшняя лекция будет посвящена более полному описанию структуры модуля. Но, вначале, продолжая тему функционального программирования, хочу остановиться на некоторых аспектах построения методов.
В классическом функциональном программировании информация в функцию передается через параметры функции, а результаты, вычисленные функцией, представлены значением, возвращаемым функцией. Поскольку в роли возвращаемого значения может быть список, содержащий объекты разных типов, то нет ограничений на число результатов, вычисляемых функцией, и их типы. Формально, и функции могли бы иметь один параметр - список, в котором функции передавалась бы вся необходимая ей информация. Возможность упаковки множества параметров в список - хороший прием, но он усложняет понимание того, что делает метод. Поскольку параметры имеют разный смысл и могут быть разных типов, то удобнее, конечно, иметь множество параметров. Возможность иметь параметры, значения которых задаются по умолчанию, иметь параметр, которому ставится в соответствие кортеж фактических параметров, существенно облегчает разработку.
В практическом программировании в отличие от классики применяются разные способы передачи информации в функцию и возвращения результатов работы функции. Мы уже видели на примере метода сортировки списка, что метод может быть интересен не возвращаемым результатом, а побочным эффектом. В этом случае метод является процедурой, - в его теле отсутствует оператор return и вызывается он как процедура. Входной параметр, представляющий ссылку на список, остается неизменным, а сам объект список изменяется. Такой способ передачи информации из функции широко применяется на практике.
В лекции по функциональному программированию мы определили функцию высшего порядка Integral, вычисляющую значение определенного интеграла, которой в качестве формального параметра передавалась подынтегральная функция. Тогда мы упростили задачу, полагая, что подынтегральная функция зависит только от одного аргумента. На практике подынтегральная функция может зависеть от многих параметров. Например, используемая нами функция f(x) = 2x + 1 является частным случаем линейной функции ax + b, для вычисления значений которой в общем случае требуется знать не только аргумент x, но и значения параметров a и b. Рассматриваемая там же функция g(x) является частным случаем квадратичной функции, у которой помимо x есть еще три параметра. Функция F(x) = f(g(x)), представляющая суперпозицию функций, также имеет три параметра - аргумент x и два параметра, задающие функции, участвующие в
суперпозиции. Как передать эту информацию функции высшего порядка Integral, учитывая, что разным подынтегральным функциям требуется разнородная информация. Рассмотрим способы решения этой задачи.
Начнем с классического варианта, когда для передачи информации используются входные параметры. Будем полагать, что подынтегральная функция - это функция от двух параметров. Первый параметр - это параметр x, - точка, в которой вычисляется функция. А второй параметр params - это список, содержащий всю необходимую дополнительную информацию. Это изменение в малой степени коснется функции Integral, - параметр params появится в списке формальных параметров и будет передаваться подынтегральной функции при ее вызове.
def Integral_M(a: float, b: float, f, params: list, eps: float)-> float:
"""
Вычисление определенного интеграла на интервале [a, b]
с подынтегральной функцией f(x, params).
Интеграл вычисляется как площадь.
eps - точность вычислений
"""
n = 1; d = b - a; s0 = -1; h = d/2
sf = (math.fabs(f(a, params)) + math.fabs(f(b, params)))/2
s1 = sf * d
while math.fabs(s1 - s0) > eps:
for i in range(n):
sf += math.fabs(f(a + h + 2 * i * h, params))
s0 = s1; s1 = sf * h; n = 2 * n; h = h /2
return s1
Это небольшое изменение существенно расширило возможности функции Integral, позволяя вычислять интеграл для более широкого класса подынтегральных функций. Вот несколько примеров вызова обновленной функции Integral_M. Подынтегральные функции во всех примерах задаются с помощью лямбда определений:
import math
def f(x: float)-> float:
return 2 * x + 1
def g(y: float)-> float:
return y * y + 4 * y - 5
def F (x: (int, float), f, g)-> float:
"""
Функция как объект. F- Функция высших порядков - аргументы f, g являются функциями
"""
return f(g(x))
def test1():
"""
Вызовы обновленной функции Integral_M
Подынтегральные функции задаются с использованием лямбда определений
"""
eps = 1e-7
pars = [2, 1]
mix = Integral_M(0, 2, lambda x, pars: pars[0] * x + pars[1], pars, eps )
print(mix)
pars = [1, 4, -5]
mix = Integral_M(0, 2, lambda x, pars: pars[0] *x *x + pars[1] * x + pars[2], pars, eps)
print(mix)
pars = [f, g]
mix = Integral_M(0, 2, lambda x, pars: pars[0](pars[1](x)), pars, eps)
print(mix)
test1()
Вот результаты работы:
Начнем с определения глобальных и локальных имен. Имена формальных параметров метода и все имена, определенные в теле метода, являются локальными именами метода. Область их видимости - тело метода. Вне метода эти имена не видимы. Время жизни локальных имен начинается с момента определения в теле метода и заканчивается в момент завершения выполнения метода. Локальные переменные существуют только тогда, когда метод вызывается на выполнение и исчезают, когда метод завершает работу. "Мавр сделал свое дело, мавр должен уйти"! Напомню, когда имени в теле метода присваивается значение, то это имя считается локальной переменной метода, имя связывается с объектом, забывая о том значении, которое оно могло иметь до выполнения присваивания.
Имя метода в отличие от имен формальных параметров является глобальным, - оно определено на уровне модуля и область его видимости - это весь модуль. Ранее мы не акцентировали на этом внимание, считая по умолчанию, что в теле метода можно вызывать любой метод, определенный в модуле. Это возможно только потому, имена методов модуля - это глобальные имена, видимые во всем модуле, и время их жизни совпадает со временем жизни модуля.
Глобальными являются не только имена методов, но и имена переменных, определенные на уровне модуля в программном коде, включенном в модуль.
Глобальные переменные модуля называются атрибутами модуля. Их значения определяют текущее состояние модуля. Атрибуты модуля также как и имена методов доступны во всем модуле, в том числе в теле любого метода. Это позволяет ввести еще один важный способ обмена информацией между модулем и методом модуля. Метод может использовать глобальные переменные для получения необходимой ему информации. Метод может не иметь параметров, получая всю необходимую информацию через глобальные переменные. Эта концепция модуля языка Python во многом схожа с концепцией ООП. В объектно-ориентированном программировании переменные, объявленные на уровне класса, являются полями класса, доступными для всех методов класса. Поля класса служат двум целям:
В языке Python переменные, введенные на уровне модуля, также можно рассматривать как поля или атрибуты модуля и полагать, что они играют ту же роль, что и поля класса в ООП.
Приведу пример использования глобальных переменных для передачи информации в функцию. Приведу еще одну модификацию функции высшего порядка Integral. Ранее в модификации этой функции Integral_M мы добавили формальный параметр, который передавался подынтегральной функции. Сейчас же в модификации Integral_S оставим только один параметр - имя подынтегральной функции, передавая всю остальную информацию через атрибуты модуля - глобальные переменные. Приведу вначале текст функции Integral_S:
def Integral_S(f)-> float:
"""
Вычисление определенного интеграла на интервале [a, b]
Интеграл вычисляется как площадь.
eps - точность вычислений
"""
n = 1; d = b - a; s0 = -1; h = d/2
sf = (math.fabs(f(a)) + math.fabs(f(b)))/2
s1 = sf * d
while math.fabs(s1 - s0) > eps:
for i in range(n):
sf += math.fabs(f(a + h + 2 * i * h))
s0 = s1; s1 = sf * h; n = 2 * n; h = h /2
return s1
В этой модификации мы снова вернулись к варианту, когда подынтегральная функция рассматривается как функция от одного аргумента. Всю остальную информацию она получает через глобальные переменные модуля. Приведу описание атрибутов модуля:
# Объявления переменных на уровне модуля a = 0 b = 2 A = 1 B = 4 C = -5 eps = 1e-7
Вот пример функции, которая при вычислении значения использует глобальную информацию:
def fun(x):
return A * x * x + B * x + C
Построим теперь интерфейсный метод, тестирующий работу функции Integral_S:
def test2():
"""
Обмен информацией через глобальные переменные
"""
mix = Integral_S(lambda x: A * x * x + B * x + C)
print("Функция, использующая глобальные переменные:", mix)
mix = Integral_S(fun)
print("Функция, использующая глобальные переменные:", mix)
test2()
Вот результаты выполнения:
Мы рассмотрели два крайних случая. В одном случае вся входная информация методу передается через механизм формальных - фактических параметров, в другом - большая часть входных данных передается через механизм атрибутов модуля - механизм глобальных переменных. Какой из этих способов предпочтительнее. Однозначного ответа нет. Недостатком классического функционального программирования, когда вся информация передается через формальные параметры, является появление большого числа параметров у функций. Представьте функция F - функция высшего порядка с функциональными аргументами f, g. Тогда вся входная информация, необходимая этим функциям, должна быть передана функции F, как это было с параметром params у функции Integral_M. В языке Python этот недостаток нивелируется тем, что при вызове передаются только ссылки, а не сами тяжелые объекты. Кроме того, есть приятная возможность при вызове задавать не все параметры, используя концепцию параметров по умолчанию.
В рассматриваемом нами случае разумным компромиссом было бы включить параметры a, b, eps в число формальных параметров метода Integral_B, задав их как параметры по умолчанию. Что же касается параметра params, то лучше предоставить решение пользователю, создав две модификации метода Integral с такими, например, заголовками:
def Integral_B1(f, a = 0, b = 1, eps = 1e-7 ):
pass
def Integral_B2(f, params, a = 0, b = 1, eps = 1e-7 ):
pass
Здесь тело метода представлено заглушкой pass, представляющей пустой оператор языка Python , который не выполняет никаких действий.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.