Неужели не нашлось русских специалистов, чтобы записать курс по пайтону ? Да, можно включить переводчик и слушать с переводом, но это что? Это кто-то считает хорошим и понятным курсом для начинающих? |
Методы
Смотреть на youtube
На прошлом разделе данной лекции мы рассмотрели понятие метода в языке Python, мы изучили как определяются методы, как они вызываются, когда метод реализован как функция, когда как процедура. Были рассмотрены различные примеры определения функций и процедур. Первое знакомство с этими понятиями уже состоялось. Сегодня продолжим рассмотрение этих понятий, начнем с подведения итогов предыдущей лекции. Теперь, когда эти понятия содержательно понятны, дадим более строгое определение синтаксиса и семантики определения метода и вызова метода.
Синтаксис и семантика определения метода
Синтаксис будем определять, используя правила контекстно свободной грамматики, имеющие вид:
<понятие> ::= <определения понятия>
В левой части правила задается определяемое понятие, в правой части - его определение через другие понятия. Символ "::= " интерпретируется как "это есть".
<определение метода> ::= <заголовок метода> <тело метода> <заголовок метода> ::= def <имя метода> (<список формальных параметров>): <список формальных параметров> ::= [<part1>] [<part2>] [<part3>] <part1> ::= <список имен> <part2> ::= <* имя> <part3> ::= <список пар: имя = значение по умолчанию> <тело метода> ::= <последовательность операторов на одном уровне отступа>
Заголовок метода принято размещать на отдельной строке. Квадратные скобки в правиле для списка формальных параметров означают, что каждая из трех частей списка формальных параметров может отсутствовать, но, если части присутствуют, то они следуют в установленном порядке.
Как по определению метода узнать, задает ли метод функцию или процедуру? Синтаксис заголовка метода не позволяет этого сделать - синтаксис одинаков. Все параметры считаются входными, выходных параметров нет.
Тело метода позволяет обнаружить разницу. Если в теле метода нет оператора return, то метод задает процедуру, его вызов задается оператором вызова, таким же, как уже изученные операторы языка - присваивания, выбора, цикла.
Если оператор return присутствует, то тут возможны две ситуации. В первой - метод реализует классическую функцию. По входным параметрам вычисляется значение функции и оператор return возвращает это значение в качестве результата функции. Этот оператор является последним выполняемым оператором тела функции. Вызов метода в этом случае является первичным выражением и может встречаться всюду, где по синтаксису допустимо использование выражения.
Во второй ситуации метод может реализовать функцию с побочным эффектом. С одной стороны, он возвращает результат вычисления функции. В качестве побочного эффекта изменяется один или несколько объектов, переданных в момент вызова в качестве фактических параметров. Типичный пример - методу в качестве входного параметра передается массив, метод сортирует массив, а в качестве результата возвращает список трех первых элементов отсортированного списка - список трех призеров. Такой метод может вызываться и как функция, если нас интересуют в первую очередь призеры. Метод может вызываться как процедура, если нам важен сам отсортированный список, а не первые его элементы.
Итак, содержательно определение метода может задавать одну из трех возможностей: функцию, процедуру, функцию с побочным эффектом.
Синтаксис и семантика вызова метода.
<вызов метода> ::= <имя метода>(<список фактических параметров>) <фактический параметр> ::= <имя, ссылающееся на объект> | <выражение>
Синтаксически вызов процедуры или функции не различаются. Различие содержится в точке, задающей место вызова. Вызов процедуры - это оператор языка и его место среди других операторов. Вызов функции - это выражение, и его место там, где положено быть выражению.
Семантика вызова предполагает, что в момент вызова устанавливается соответствие между формальными и фактическими параметрами. В предыдущей лекции мы подробно говорили, как устанавливается соответствие между формальным параметром и фактическим для всех возможных трех частей списка формальных параметров.
Заметьте, для первой части формальных параметров мы рассматривали только одну форму вызова фактических параметров - позиционную, когда k-му формальному параметру соответствует k-й фактический параметр. Однако для параметров первой части возможен именованный способ вызова фактических параметров, имеющий вид:
<вызов метода> ::= <имя метода>(<список пар: формальный параметр = фактический параметр>)
В этом случае порядок записи формальных параметров не имеет значения в точке вызова. Эта форма вызова соответствует форме вызова параметров, задаваемых по умолчанию, порядок записи именованных параметров не имеет значения.
Остановимся на том, что происходит в момент вызова, когда формальному параметру, представляющему имя, ставится в соответствие фактический параметр, который может быть именем или выражением.
Если фактический параметр - это имя, представляющее ссылку на объект, то в момент вызова формальный параметр связывается с объектом, заданным фактическим параметром, результатом будут две ссылки на один объект. При выполнении тела метода действия над формальным параметром будут фактически производиться над объектом, заданным фактическим параметром.
В предыдущей лекции подробно обсуждался тот факт, что метод не может разорвать связь между именем фактического параметра и объектом, на который имя указывает. При попытке в теле метода присвоить новый объект формальному параметру связь между формальным параметром и фактическим разрывается. Формальный параметр становится локальной переменной, получившей новое значение. По завершении метода локальная переменная перестает существовать, а имя фактического параметра по-прежнему связано с объектом момента вызова.
Если фактический параметр - это некоторое выражение, то в момент вызова вычисляется это выражение, в результате создается новый объект и имя формального параметра связывается с этим объектом, являясь ссылкой на созданный объект. При выполнении тела метода действия над формальным параметром будут фактически производиться над созданным объектом.
Давайте построим пример функции с двумя формальными параметрами, при вызове которой одному параметру передадим имя фактического параметра, другому - выражение. Функцию построим простую, параметрами будут списки, а возвращаемым значением - список из двух элементов - максимальных элементов каждого списка.
Вот соответствующий код, содержащий описание трех методов - двух функций и одной процедуры, и одного оператора вызова процедуры:
def Max(ar): max = ar[0] for item in ar: if item > max: max = item return max def TwoMax(a, b): max1 = Max(a) max2 = Max(b) return [max1, max2] def test7(): d = [7, 12, 4, 21, 18] e = [6, 14, 12, 3] f = [3, 9, 27, 16 ] two = TwoMax(d, e + f) print("max1 = ", two[0], " max2 = ", two[1]) test7()
Давайте подробно разберем, как выполняется данный код. В модуле, запускаемом на выполнение, содержатся описания ряда методов и операторы вызова некоторых методов, представляющих процедуры. Перед каждым запуском модуля операторы вызова процедур комментируются за исключением одного, который и запускает соответствующий тест. В данном случае определен метод test7, который является процедурой. Его описание предшествует оператору вызова процедуры test7(), так что оператор вызова, обнаружив процедуру, вызывает ее на выполнение, не передавая ей никаких параметров. Заметьте, в списке формальных параметров все части: part1, part2, part3 могут отсутствовать.
При выполнении тела процедуры создаются три локальные переменные - d, e, f, каждая из которых связывается с соответствующим списком. Далее процедура test7 вызывает функцию TwoMax, передавая ей в качестве фактических параметров имя d и выражение e + f. В момент вызова при установлении соответствия между формальными и фактическими параметрами имена a и d становятся псевдонимами, ссылающиеся на один и тот же объект. Имя b становится ссылкой на новый объект - список, полученный конкатенацией списков e и f.
При выполнении тела функции TwoMax дважды вызывается функция Max. При первом вызове имя a передается в качестве фактического параметра. В результате псевдонимами становятся три имени: ar, a, d. Функция возвращает в качестве результата максимальный элемент списка, связанного с именем d - 21. При втором вызове функции Max имя ar становится псевдонимом имени b, в качестве результата возвращается максимальный элемент списка, полученный конкатенацией списков e и f - 27.
Вот результаты работы:
Заметьте, тот же результат вызова функции TwoMax был бы получен, если в тестовой процедуре использовалась именованная форма вызова:
two = TwoMax( b = e + f, a = d)