На уроке объясняется синтаксис составления процедуры и функции Питон. Рассматривается вызов функции, параметры функции и процедуры
Содержание:
- Функции в роли процедуры
- Процедура с параметрами
- Локальные и глобальные переменные
- Язык Python функции
Функции в роли процедуры
return).Рассмотрим синтаксис функции-процедуры на примере:
Пример: Создать процедуру для вывода сообщения об ошибке. Запрашивать у пользователя ввести положительное число, в случае ввода отрицательного числа, вызывать процедуру для вывода сообщения об ошибке.
✍ Решение:
def Err(): # определение процедуры print ( "Ошибка: неверные данные" ) n = int ( input('введите положительное число') ) if n < 0: Err() # вызов процедуры
- Процедура — вспомогательный алгоритм, выполняющий некоторые действия.
- Это поименованный фрагмент программы, который можно вызвать.
- Процедура должна быть определена к моменту её вызова. Определение процедуры начинается со служебного слова def.
- Вызов процедуры осуществляется по ее имени, за которым следуют круглые скобки, например, Err().
- В одной программе может быть сколько угодно много вызовов одной и той же процедуры.
- Использование процедур сокращает код и повышает удобочитаемость.
Процедура с параметрами
Как используются в Python параметры процедуры, рассмотрим на примере.
Пример: Написать процедуру, которая печатает 60 раз указанный символ (введенный с клавиатуры), каждый с новой строки.
✍ Решение:
1 2 3 4 5 |
def printChar(s): for i in range(60): print (s) sim = input('введите символ') printChar(sim) |
- Глобальная переменная — если ей присвоено значение в основной программе (вне процедуры).
- Локальная переменная (внутренняя) известна только на уровне процедуры, обратиться к ней из основной программы и из других процедур нельзя.
- Параметры процедуры — локальные переменные. В программе s — локальная переменная.
Задание Python 3_0:
Создать процедуру, которая вычисляет разность двух вводимых пользователем числа. Выполнить задание двумя способами: 1) процедура без параметров: числа — глобальные переменные, определенные в основной программе; 2) процедура с параметрами: числа — параметры процедуры.
Локальные и глобальные переменные
Примеры использования локальных и глобальных переменных:
1 2 3 4 |
x = 3 # глобальная переменная def pr(): # процедура без параметров print (x) # вывод значения глобальной переменной pr() |
1 2 3 4 5 |
x = 3 # глобальная переменная def pr(a): # процедура с параметром a = 4 # локальная переменная print (a) # 4 pr(x) # передача параметра глобальной переменной (3) |
1 2 3 4 5 6 |
x = 3 # глобальная переменная def pr(): # процедура без параметров global x x = 1 print (x) # вывод измененного значения глобальной переменной (1) pr(x) |
Задание Python 3_1:
Напишите процедуру, которая выводит на экран в столбик все цифры переданного ей числа, начиная с последней:
число: 4673 результат: 3 7 6 4
Задание Python 3_2:
Напишите процедуру, которая выводит на экран все делители переданного ей числа (в одну строчку).
Задание Python 3_3:
Составить программу с процедурой для вычисления степени числа (входные параметры: число и степень).
Рекомендации: для вычисления степени числа можно использовать функцию pow(число, степень)
Задание Python 3_4:
Напишите процедуру, которая принимает параметр – натуральное число N – и выводит первые N чисел Фибоначчи.
Пример использования ключевого слова global:
Поменять значений двух переменных.
✍ Решение:
-
Решение 1:
def Swap(): global x,y t = x x = y y = t x=3 y=5 Swap() print(x,y)
Решение 2:
def Swap(): global x,y (x, y) = (y, x) (x,y)=(3,5) Swap() print(x,y)
Задание Python 3_5:
Создайте процедуру без параметров AddLeftDigit(), которая добавляет введенную цифру K (0<=K<=9) слева к введенной цифре D (0<=D<=9) и выводит результат. Используйте ключевое слово global для работы с глобальными переменными.
Ожидаемый результат:
введите D (0<=D<=9) и K(0<=K<=9): >>>2 >>>4 результат: 42
Часть функций языка Python являются встроенными функциями, которые обеспечены синтаксисом самого языка. Например, int, input, randint.
Рассмотрим пример создания пользовательских функций.
- Функция — это поименованный фрагмент программы, который можно вызвать.
- Как и процедура, функция должна быть определена к моменту её вызова (служебное слово def).
- Функция в отличии от процедуры возвращает значение.
- Для возврата значения функции используется оператор return.
- Вызов функции осуществляется по ее имени и обычно сопровождается выводом значения.
Пример:
Найти максимальное значение из значений двух переменных.
✍ Решение:
def max(a,b): if(a>b): return a else: return b x=int(input()) y=int(input()) print('max = ',max(x,y))
Задание Python 3_6:
Создайте функцию для поиска минимума среди трех чисел (три параметра функции).
Пример:
Вычислить сумму цифр числа.
1 2 3 4 5 6 7 8 |
def sumD(n): # определение функции с параметром sum = 0 while n!= 0: sum += n % 10 n = n // 10 return sum # возврат значения функции # основная программа print (sumD(1075)) # вызов функции с параметром |
Задание Python 3_7:
Напишите функцию, которая вычисляет количество цифр числа.
Задание Python 3_8:
Создайте функцию, которая вычисляет сумму всех чисел от 1 до N. N — параметр функции.
Задание Python 3_9:
Напишите функцию, которая вычисляет факториал натурального числа N.
Содержание:
- Функции в Python
-
-
- Листинг 1. Определения функций
-
-
- Variable-length arguments
- Процедуры
- Процедура с параметрами
- Локальные и глобальные переменные
- Defining a Function
- Несколько простейших примеров
-
-
- Листинг 4. Операторное (императивное) определение факториала
-
-
- Циклы
- Keyword arguments
- The Anonymous Functions
- Default arguments
- Заключение
-
- Похожие темы
-
Функции в Python
Функции в Python определяются 2-мя способами: через определение
или через анонимное описание . Оба этих способа
определения доступны, в той или иной степени, и в некоторых других языках программирования. Особенностью
Python является то, что функция является таким же именованным объектом, как и любой другой объект некоторого
типа данных, скажем, как целочисленная переменная. В листинге 1 представлен простейший пример (файл
func.py из архива python_functional.tgz в разделе «Материалы для скачивания»):
Листинг 1. Определения функций
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
def show( fun, arg ):
print( '{} : {}'.format( type( fun ), fun ) )
print( 'arg={} => fun( arg )={}'.format( arg, fun( arg ) ) )
if len( sys.argv ) > 1: n = float( sys.argv )
else: n = float( input( "число?: " ) )
def pow3( n ): # 1-е определение функции
return n * n * n
show( pow3, n )
pow3 = lambda n: n * n * n # 2-е определение функции с тем же именем
show( pow3, n )
show( ( lambda n: n * n * n ), n ) # 3-е, использование анонимного описание функции
При вызове всех трёх объектов-функций мы получим один и тот же результат:
$ python func.py 1.3 <type 'function'> : <function pow3 at 0xb7662844> arg=1.3 => fun( arg )=2.197 <type 'function'> : <function <lambda> at 0xb7662bc4> arg=1.3 => fun( arg )=2.197 <type 'function'> : <function <lambda> at 0xb7662844> arg=1.3 => fun( arg )=2.197
Ещё более отчётливо это проявляется в Python версии 3, в которой всё является классами (в том числе, и
целочисленная переменная), а функции являются объектами программы, принадлежащими к классу
:
$ python3 func.py 1.3 <class 'function'> : <function pow3 at 0xb74542ac> arg=1.3 => fun( arg )=2.1970000000000005 <class 'function'> : <function <lambda> at 0xb745432c> arg=1.3 => fun( arg )=2.1970000000000005 <class 'function'> : <function <lambda> at 0xb74542ec> arg=1.3 => fun( arg )=2.1970000000000005
Примечание. Существуют ещё 2 типа объектов, допускающих функциональный вызов —
функциональный метод класса и функтор, о которых мы поговорим позже.
Если функциональные объекты Python являются такими же объектами, как и другие объекты данных, значит,
с ними можно и делать всё то, что можно делать с любыми данными:
- динамически изменять в ходе выполнения;
- встраивать в более сложные структуры данных (коллекции);
- передавать в качестве параметров и возвращаемых значений и т.д.
На этом (манипуляции с функциональными объектами как с объектами данных) и базируется функциональное
программирование. Python, конечно, не является настоящим языком функционального программирования, так,
для полностью функционального программирования существуют специальные языки: Lisp, Planner, а из более
свежих: Scala, Haskell. Ocaml, … Но в Python можно «встраивать» приёмы функционального программирования в
общий поток императивного (командного) кода, например, использовать методы, заимствованные из
полноценных функциональных языков. Т.е. «сворачивать» отдельные фрагменты императивного кода (иногда
достаточно большого объёма) в функциональные выражения.
Временами спрашивают: «В чём преимущества функционального стиля написания отдельных фрагментов
для программиста?». Основным преимуществом функционального программирования является то, что после
однократной отладки такого фрагмента в нём при последующем многократном использовании не возникнут
ошибки за счёт побочных эффектов, связанных с присвоениями и конфликтом имён.
Достаточно часто при программировании на Python используют типичные конструкции из области
функционального программирования, например:
print ( )
В результате запуска получаем:
$ python funcp.py
Variable-length arguments
You may need to process a function for more arguments than you specified while defining the function. These arguments are called variable-length arguments and are not named in the function definition, unlike required and default arguments.
Syntax for a function with non-keyword variable arguments is this −
def functionname( *var_args_tuple ): "function_docstring" function_suite return
An asterisk (*) is placed before the variable name that holds the values of all nonkeyword variable arguments. This tuple remains empty if no additional arguments are specified during the function call. Following is a simple example −
#!/usr/bin/python
# Function definition is here
def printinfo( arg1, *vartuple ):
"This prints a variable passed arguments"
print "Output is: "
print arg1
for var in vartuple:
print var
return;
# Now you can call printinfo function
printinfo( 10 )
printinfo( 70, 60, 50 )
When the above code is executed, it produces the following result −
Output is: 10 Output is: 70 60 50
Процедуры
Подпрограммы прежде всего необходимы в ситуации, когда в разных частях программы необходимо выполнять одни и те же действия несколько раз. В таком случае повторяемые операторы оформляются в виде функции или процедуры, к которой можно обращаться и вызывать ее выполнение из разных частей программы.
В python существует два вида реализации подпрограмм: процедуры и функции.
Рассмотрим синтаксис процедуры на примере:
Пример: Создать процедуру для вывода сообщения об ошибке. Запрашивать у пользователя ввести положительное число, в случае ввода отрицательного числа, вызывать процедуру для вывода сообщения об ошибке.
Решение:
def Err(): # определение процедуры
print ( "Ошибка: неверные данные" )
n = int ( input('введите положительное число') )
if n < :
Err() # вызов процедуры
- Процедура — вспомогательный алгоритм, выполняющий некоторые действия.
- Это поименованный фрагмент программы, который можно вызвать.
- Процедура должна быть определена к моменту её вызова. Определение процедуры начинается со служебного слова def.
- Вызов процедуры осуществляется по ее имени, за которым следуют круглые скобки, например, Err().
- В одной программе может быть сколько угодно много вызовов одной и той же процедуры.
- Использование процедур сокращает код и повышает удобочитаемость.
Процедура с параметрами
Как используются в Python параметры процедуры, рассмотрим на примере.
Пример: Написать процедуру, которая печатает 60 раз указанный символ (введенный с клавиатуры), каждый с новой строки.
Решение:
1 2 3 4 5 |
def printChar(s):
for i in range(60):
print (s)
sim = input('введите символ')
printChar(sim)
|
- Глобальная переменная — если ей присвоено значение в основной программе (вне процедуры).
- Локальная переменная (внутренняя) известна только на уровне процедуры, обратиться к ней из основной программы и из других процедур нельзя.
- Параметры процедуры — локальные переменные. В программе s — локальная переменная.
Задание Python 3_0:
Создать процедуру, которая вычисляет разность двух вводимых пользователем числа. Выполнить задание двумя способами: 1) процедура без параметров: числа — глобальные переменные, определенные в основной программе; 2) процедура с параметрами: числа — параметры процедуры.
Локальные и глобальные переменные
Примеры использования локальных и глобальных переменных:
1 2 3 4 |
x = 3 # глобальная переменная def pr(): # процедура без параметров print (x) # вывод значения глобальной переменной pr() |
1 2 3 4 5 |
x = 3 # глобальная переменная def pr(a): # процедура с параметром a = 4 # локальная переменная print (a) # 4 pr(x) # передача параметра глобальной переменной (3) |
Существует возможность изменить значение глобальной переменной (не создавая локальную). В процедуре с помощью слова global:
1 2 3 4 5 6 |
x = 3 # глобальная переменная def pr(): # процедура без параметров global x x = 1 print (x) # вывод измененного значения глобальной переменной (1) pr(x) |
Задание Python 3_1:
Напишите процедуру, которая выводит на экран в столбик все цифры переданного ей числа, начиная с последней:
число: 4673 результат: 3 7 6 4
Задание Python 3_2:
Напишите процедуру, которая выводит на экран все делители переданного ей числа (в одну строчку).
Задание Python 3_3:
Составить программу с процедурой для вычисления степени числа (входные параметры: число и степень).
Задание Python 3_4:
Напишите процедуру, которая принимает параметр – натуральное число N – и выводит первые N чисел Фибоначчи.
Defining a Function
You can define functions to provide the required functionality. Here are simple rules to define a function in Python.
-
Function blocks begin with the keyword def followed by the function name and parentheses ( ( ) ).
-
Any input parameters or arguments should be placed within these parentheses. You can also define parameters inside these parentheses.
-
The first statement of a function can be an optional statement — the documentation string of the function or docstring.
-
The code block within every function starts with a colon (:) and is indented.
-
The statement return exits a function, optionally passing back an expression to the caller. A return statement with no arguments is the same as return None.
Несколько простейших примеров
Выполним несколько простейших трансформаций привычного императивного кода (командного,
операторного) для превращения его отдельных фрагментов в функциональные. Сначала заменим операторы
ветвления логическими условиями, которые за счёт «отложенных» (lazy, ленивых) вычислений позволяют
управлять выполнением или невыполнением отдельных ветвей кода. Так, императивная конструкция:
if <условие>:
<выражение 1>
else:
<выражение 2>
— полностью эквивалентна следующему функциональному фрагменту (за счёт «отложенных» возможностей
логических операторов и ):
# функция без параметров: lambda: ( <условие> and <выражение 1> ) or ( <выражение 2> )
В качестве примера снова используем вычисление факториала. В листинге 4 приведен функциональный код
для вычисления факториала (файл fact1.py в архиве python_functional.tgz в
разделе «Материалы для скачивания»):
Листинг 4. Операторное (императивное) определение факториала
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
def factorial( n ):
if n == 1: return 1
else: return n * factorial( n - 1 )
if len( sys.argv ) > 1:
n = int( sys.argv )
else:
n = int( input( "число?: " ) )
print( "n={} => n!={}".format( n, factorial( n ) ) )
Аргумент для вычисления извлекается из значения параметра командной строки (если он есть) или вводится
с терминала. Первый вариант изменения, показанный выше, уже применяется в листинге 2, где на
функциональные выражения были заменены:
-
определение функции факториала:
factorial = lambda x: ( ( x == 1 ) and 1 ) or x * factorial( x - 1 )
-
запрос на ввод значения аргумента с консоли терминала:
arg = lambda : ( len( sys.argv ) > 1 and int( sys.argv ) ) or int( input( "число?: " ) ) n = arg()
В файле fact3.py появляется ещё одно определение функции, сделанное через функцию
высшего порядка :
factorial = factorial = lambda z: reduce( lambda x, y: x * y, range( 1, z + 1 ) )
Здесь же мы упростим также и выражение для , сведя его к
однократному вызову анонимной (не именованной) функции:
n = ( lambda : ( len( sys.argv ) > 1 and int( sys.argv ) ) or
int( input( "число?: " ) ) )()
Наконец, можно заметить, что присвоение значения переменной
требуется только для её использования в вызове для вывода
этого значения. Если мы откажемся и от этого ограничения, то всё приложение выродится в один
функциональный оператор (см. файл fact4.py в архиве python_functional.tgz в
разделе «Материалы для скачивания»):
from sys import *
from functools import reduce
print( 'вычисленный факториал = {}'.format(
( lambda z: reduce( lambda x, y: x * y, range( 1, z + 1 ) ) )
( ( lambda : ( len( argv ) > 1 and int( argv ) ) or
int( input( "число?: " ) ) )() ) ) )
Этот единственный вызов внутри функции и представляет
всё приложение в его функциональном варианте:
$ python3 fact4.py число?: 5 вычисленный факториал = 120
Читается ли этот код (файл fact4.py) лучше, чем императивная запись (файл fact1.py)? Скорее нет, чем да. В
чём же тогда его достоинство? В том, что при любых изменениях окружающего его кода,
нормальная работа этого фрагмента сохранится, так как отсутствует риск побочных эффектов
из-за изменения значений используемых переменных.
Циклы
Перед тем, как мы ознакомимся с тем, как работает range(), нам нужно взглянуть на то, как работают циклы. Циклы — это ключевая концепция компьютерных наук. Если вы хотите стать хорошим программистом, умение обращаться с циклами — это важнейший навык, который стоит освоить.
Рассмотрим пример цикла for в Python:
Python
captains =
for captain in captains:
print(captain)
|
1 |
captains=’Janeway’,’Picard’,’Sisko’ forcaptain incaptains print(captain) |
Выдача выглядит следующим образом:
Python
Janeway
Picard
Sisko
|
1 |
Janeway Picard Sisko |
Как вы видите, цикл for позволяет вам выполнять определенные части кода, столько раз, сколько вам угодно. В данном случае, мы зациклили список капитанов и вывели имена каждого из них.
Хотя Star Trek — отличная тема и все такое, вам может быть нужен более сложный цикл, чем список капитанов. Иногда вам нужно просто выполнить часть кода определенное количество раз. Циклы могут помочь вам с этим.
Попробуйте запустить следующий код с числами, кратными трем:
Python
numbers_divisible_by_three =
for num in numbers_divisible_by_three:
quotient = num / 3
print(f»{num} делится на 3, результат {int(quotient)}.»)
|
1 |
numbers_divisible_by_three=3,6,9,12,15 fornum innumbers_divisible_by_three quotient=num3 print(f»{num} делится на 3, результат {int(quotient)}.») |
Выдача цикла будет выглядеть следующим образом:
Python
3 делится на 3, результат 1.
6 делится на 3, результат 2.
9 делится на 3, результат 3.
12 делится на 3, результат 4.
15 делится на 3, результат 5.
|
1 |
3делитсяна3,результат1. 6делитсяна3,результат2. 9делитсяна3,результат3. 12делитсяна3,результат4. 15делитсяна3,результат5. |
Это выдача, которая нам нужна, так что можем сказать, что цикл выполнил работу адекватно, однако есть еще один способ получения аналогично результата: использование range().
Теперь, когда вы знакомы с циклами поближе, посмотрим, как вы можете использовать range() для упрощения жизни.
Keyword arguments
Keyword arguments are related to the function calls. When you use keyword arguments in a function call, the caller identifies the arguments by the parameter name.
This allows you to skip arguments or place them out of order because the Python interpreter is able to use the keywords provided to match the values with parameters. You can also make keyword calls to the printme() function in the following ways −
#!/usr/bin/python # Function definition is here def printme( str ): "This prints a passed string into this function" print str return; # Now you can call printme function printme( str = "My string")
When the above code is executed, it produces the following result −
My string
The following example gives more clear picture. Note that the order of parameters does not matter.
#!/usr/bin/python # Function definition is here def printinfo( name, age ): "This prints a passed info into this function" print "Name: ", name print "Age ", age return; # Now you can call printinfo function printinfo( age=50, name="miki" )
When the above code is executed, it produces the following result −
Name: miki Age 50
The Anonymous Functions
These functions are called anonymous because they are not declared in the standard manner by using the def keyword. You can use the lambda keyword to create small anonymous functions.
-
Lambda forms can take any number of arguments but return just one value in the form of an expression. They cannot contain commands or multiple expressions.
-
An anonymous function cannot be a direct call to print because lambda requires an expression
-
Lambda functions have their own local namespace and cannot access variables other than those in their parameter list and those in the global namespace.
-
Although it appears that lambda’s are a one-line version of a function, they are not equivalent to inline statements in C or C++, whose purpose is by passing function stack allocation during invocation for performance reasons.
Default arguments
A default argument is an argument that assumes a default value if a value is not provided in the function call for that argument. The following example gives an idea on default arguments, it prints default age if it is not passed −
#!/usr/bin/python # Function definition is here def printinfo( name, age = 35 ): "This prints a passed info into this function" print "Name: ", name print "Age ", age return; # Now you can call printinfo function printinfo( age=50, name="miki" ) printinfo( name="miki" )
When the above code is executed, it produces the following result −
Name: miki Age 50 Name: miki Age 35
Заключение
В этой статье были представлены некоторые возможности языка Python, позволяющие применять его для
написания программ, использующих стиль функционального программирования. Так, мы описали основные
приёмы функционального программирования и показали примеры их реализации в Python. Как и в предыдущих
статьях, примеры кода написаны таким образом, что могут успешно запускаться и исполняться в обеих версиях
Python.
В следующей статье мы обсудим вопросы организации параллельного исполнения кода в среде Python.
Похожие темы
- Девид Мертц, Очаровательный Python: Функциональное программирование на языке Python, Часть 1
- Девид Мертц, Очаровательный Python: Еще о функциональном программировании на Python, Часть 2
- David Mertz, Charming Python: Functional programming in Python, Part 3
- Тонкости использования языка Python: Часть 2. Типы данных.
- Тонкости использования языка Python: Часть 4. Параллельное исполнение.
С этим файлом связано 10 файл(ов). Среди них: СЗ.docx, Положение о Центре образования естественно-научной и технологиче, Практикум по разработке учебных заданий.docx, Polozhenie o distancionnom obuchenii.rtf, Практическая работа по теме «Проектирование учебного занятия на , напрвления работы мо.docx, Отчет о проведении Месячника родного языка (1).docx, Инструкция_по_проведению_внутришкольного_мониторинга.docx, Практическая работа 1.docx, Самостоятельная 1.docx.
Показать все связанные файлы
Подборка по базе: Постановка задачи обработки информации. Основные виды, алгоритмы, 2 часть.docx, 2Первая часть практики — АТТЕСТАЦИОННЫЙ ЛИСТ ПО ПРАКТИКЕ Лукина2, Русский язык. Практическая часть № 1.docx, 2.14 Производительность системы. Часть 2 — Рыбаченко Николай..do, практическая работа №2 часть 2. Раздел 2.2.2.docx, 27 2020 ИГРОВАЯ игровой деятельности ЧАСТЬ 1 по слайдам2.docx, 1 часть.pdf, Отчёт по производственной практики Часть 2.docx, Инностранный язык (кейс) часть 3.docx
Python
ЛР 2. Часть А. Процедуры и Функции.
Подпрограммы прежде всего необходимы в ситуации, когда в разных
частях программы необходимо выполнять одни и те же действия несколько
раз. В таком случае повторяемые операторы оформляются в виде функции
или процедуры, к которой можно обращаться и вызывать ее выполнение из
разных частей программы.
В python существует два вида реализации подпрограмм: процедуры и
функции.
Рассмотрим синтаксис процедуры на примере:
Пример: создать процедуру для вывода сообщения об ошибке. Запрашивать у пользователя ввести положительное число, в случае ввода отрицательного числа, вызывать процедуру для вывода сообщения об ошибке.
✍
Решение:
def
Err
()
:
# определение процедуры
print
(
«Ошибка: неверные данные»
)
n
=
int
(
input
(
‘введите положительное число’
)
)
if
n
<
0
:
Err
()
#
вызов процедуры
•
Процедура — вспомогательный алгоритм, выполняющий некоторые действия.
•
Это поименованный фрагмент программы, который можно вызвать.
•
Процедура должна быть определена к моменту её вызова. Определение процедуры начинается со служебного слова def.
•
Вызов процедуры осуществляется по ее имени, за которым следуют круглые скобки, например, Err().
•
В одной программе может быть сколько угодно много вызовов одной и той же процедуры.
•
Использование процедур сокращает код и повышает удобочитаемость.
ПРОЦЕДУРА С ПАРАМЕТРАМИ
Как используются в Python параметры процедуры, рассмотрим на примере.
Пример: Написать процедуру, которая печатает 60 раз указанный символ (введенный с клавиатуры), каждый с новой строки.
✍
Решение:
1 2
3 4
5
def
printChar
(
s
)
:
for
i
in
range
(
60
)
:
print
(
s
)
sim
=
input
(
‘
введите символ’
)
printChar
(
sim
)
•
Глобальная переменная — если ей присвоено значение в основной программе (вне процедуры).
•
Локальная переменная (внутренняя) известна только на уровне процедуры, обратиться к ней из основной программы и из других процедур нельзя.
•
Параметры процедуры — локальные переменные. В программе s — локальная переменная.
Задание
Python
3_0:
Создать процедуру, которая вычисляет разность двух вводимых пользователем числа.
Выполнить задание двумя способами: 1) процедура без параметров: числа — глобальные переменные, определенные в основной программе; 2) процедура с параметрами: числа — параметры процедуры.
ЛОКАЛЬНЫЕ И ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
Примеры использования локальных и глобальных переменных:
1 2
3 4 x
=
3
# глобальная переменная
def
pr
()
:
# процедура без параметров
print
(
x
)
# вывод значения глобальной переменной
pr
()
1 2
3 4
5 x
=
3
# глобальная переменная
def
pr
(
a
)
:
# процедура с параметром
a
=
4
# локальная переменная
print
(
a
)
# 4
pr
(
x
)
# передача параметра глобальной переменной (3)
Существует возможность изменить значение глобальной переменной (не создавая локальную). В процедуре с помощью слова global:
1 2
3 4
5 6 x
=
3
# глобальная переменная
def
pr
()
:
# процедура без параметров
global
x x
=
1
print
(
x
)
# вывод измененного значения глобальной переменной (1)
pr
(
x
)
Задание
Python
3_1:
Напишите процедуру, которая выводит на экран в столбик все цифры переданного ей числа, начиная с последней: число: 4673 результат:
3 7
6 4
Задание
Python
3_2:
Напишите процедуру, которая выводит на экран все делители переданного ей числа (в одну строчку).
Задание
Python
3_3:
Составить программу с процедурой для вычисления степени числа (входные параметры: число и степень).
Задание
Python
3_4:
Напишите процедуру, которая принимает параметр – натуральное число N – и выводит первые N чисел Фибоначчи.
Функции
Часть функций языка Python являются встроенными функциями, которые обеспечены синтаксисом самого языка. Например, int, input, randint.
Рассмотрим пример создания пользовательских функций.
Пример:
Вычислить сумму цифр числа.
1 2
3 4
5 6
7 8
def
sumD
(
n
)
:
# определение функции с параметром
sum
=
0
while
n
!=
0
: sum
+
=
n %
10
n
=
n //
10
return
sum
# возврат значения функции
# основная программа
print
(
sumD
(
1075
))
# вызов функции с параметром
•
Функция — это поименованный фрагмент программы, который можно вызвать.
•
Как и процедура, функция должна быть определена к моменту её вызова (служебное слово def).
•
Функция в отличии от процедуры возвращает значение.
•
Для возврата значения функции используется оператор return.
•
Вызов функции осуществляется по ее имени и обычно сопровождается выводом значения.
Задание
Python
3_5:
Напишите функцию, которая вычисляет количество цифр числа.
Задание
Python
3_6:
Напишите функцию, которая вычисляет факториал натурального числа N.
Python
ЛР 2. Часть Б. Массивы (списки)
Массивы (списки) в Питоне, как и в других языках программирования,
— это определенное количество элементов одного типа, которые имеют общее имя, и каждый элемент имеет свой индекс — порядковый номер.
L — список целых чисел:
L = [25, 755, -40, 57, -41]
Однако, в языке Python отсутствует такая структура, как «массив». Для работы с
массивами используются списки.
Списки являются упорядоченными последовательностями, которые состоят из различных объектов (значений, данных), заключающихся в квадратные скобки [ ] и отделяющиеся друг от друга с помощью запятой. list
(
‘текст’
)
# [‘т’, ‘е’, ‘к’, ‘с’, ‘т’]
Создание списков на Python
Создать список можно несколькими способами. Рассмотрим их.
1. Получение списка через присваивание конкретных значений
•
Так выглядит в коде Python пустой список: s
=
[]
# Пустой список
•
Примеры создания списков со значениями: l
=
[
25
,
755
,
—
40
,
57
,
—
41
]
# список целых чисел
l
=
[
1.13
,
5.34
,
12.63
,
4.6
,
34.0
,
12.8
]
# список из дробных чисел
l
=
[
«Sveta»
,
«Sergei»
,
«Ivan»
,
«Dasha»
]
# список из строк
l
=
[
«Москва»
,
«Иванов»
,
12
,
124
]
# смешанный список
l
=
[[
0
,
0
,
0
]
,
[
1
,
0
,
1
]
,
[
1
,
1
,
0
]]
# список, состоящий из списков
l
=
[
‘s’
,
‘p’
,
[
‘isok’
]
,
2
]
# список из значений и списка
•
Списки можно складывать (конкатенировать) с помощью знака «+»: l
=
[
1
,
3
]
+
[
4
,
23
]
+
[
5
]
# Результат:
# l = [1, 3, 4, 23, 5]
2. Списки при помощи функции List()
Получаем список при помощи функции List()
l
=
list
(
‘spisok’
)
# ‘spisok’ —
строка
print
(
l
)
#[‘s’, ‘p’, ‘i’, ‘s’, ‘o’, ‘k’] —
результат — список
3. Создание списка при помощи функции Split()
•
Используя функцию split в Питон можно получить из строки список.
Рассмотрим пример: stroka
=
«Hello, world»
# stroka —
строка
lst
=
stroka.
split(
«,»
)
# lst —
список
lst
# [‘Hello’, ‘ world’]
4.
Генераторы списков
•
В python создать список можно также при помощи генераторов, — это довольно-таки новый метод: o
Первый простой способ.
Сложение одинаковых списков заменяется умножением:
# список из 10 элементов, заполненный единицами
l
=
[
1
]
*
10
#
список l = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
o
Второй способ сложнее. l
=
[
i
for
i
in
range
(
10
)]
# список l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
или такой пример: c
=
[
c *
3
for
c
in
‘list’
]
print
(
c
)
# [‘lll’, ‘iii’, ‘sss’, ‘ttt’]
Пример:
Заполнить список квадратами чисел от 0 до 9, используя генератор списка.
✍
Решение:
l
=
[
i*i
for
i
in
range
(
10
)]
еще пример: l
=
[(
i+
1
)
+i
for
i
in
range
(
10
)]
print
(
l
)
# [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
o
Случайные числа в списке:
from
random
import
randint l
=
[
randint
(
10
,
80
)
for
x
in
range
(
10
)]
# 10 чисел, сгенерированных случайным образом в диапазоне (10,80)
Задание Python 4_1:
Создайте список целых чисел от -20 до 30 (генерация).
Задание Python 4_2:
Создайте список целых чисел от -10 до 10 с шагом 2 (генерация list).
Задание Python 4_3:
Создайте список из 20 пятерок (генерация).
Задание Python 4_4:
Создайте список из сумм троек чисел от 0 до 10, используя генератор списка
(0 + 1 + 2, 1 + 2 + 3, …).
Ввод списка (массива) в языке Питон
•
Для ввода элементов списка используется цикл range:
1 2
3
for
i
in
range
(
N
)
:
print
(
«L[«
,
i
,
«]=»
,
sep
=
«»
,
end
=
«»
)
L
[
i
]
=
int
(
input
()
)
•
Более простой вариант ввода списка и его вывода:
L
=
[
int
(
input
())
for
i
in
range
(
N
)
]
Функция int здесь используется для того, чтобы строка, введенная пользователем, преобразовывалась в целые числа.
•
Как уже рассмотрено выше, список можно выводить целым и поэлементно:
# вывод целого списка (массива)
print
(
L
)
# поэлементный вывод списка (массива)
for
i
in
range
(
N
)
:
print
(
L
[
i
]
,
end
=
» «
)
Задание Python 4_5:
Заполните массив элементами арифметической прогрессии. Её первый элемент, разность и количество элементов нужно ввести с клавиатуры.
*
Формула для получения n-го члена прогрессии:
a
n
= a
1
+ (n-1) * d
Задание Python 4_6:
Заполните массив случайными числами в диапазоне 20..100 и подсчитайте отдельно число чётных и нечётных элементов.
Python
ЛР 2. Часть В. Строки.
Немного о строках
•
Строки в Питоне — это упорядоченная последовательность символов.
Строка может заключаться как в кавычки, так и в апострофы:
S
=
‘Dr»s’
S
=
«Dr’s»
•
Строка считывается со стандартного ввода функцией input(): a
=
input
()
print
(
a
)
ОПЕРАЦИИ СО СТРОКАМИ
•
Для двух строк определена
операция сложения (конкатенации), также определена
операция умножения строки на число: a
=
«
па»
b
=
«
рад»
print
(
a+b
)
#
парад
a
=
«
кар»
print
(
a*
4
)
#
каркаркаркар
Работа, как с массивами (индексация начинается с 0):
a
=
«
парад»
print
(
a
[
2
])
#
р
•
Длина строки – функция len(): a
=
«парад»
print
(
len
(
a
))
# 5
Срезы
Оператор извлечения среза из строки:
[X:Y]
X
– это индекс начала среза, а
Y
– его окончания tday
=
‘morning, afternoon, night’
tday
[
0
:
7
]
# ‘morning’
Рассмотрим примеры того, как используются в Python срезы: s
=
‘spameggs’
s
[
3
:
5
]
# ‘me’
s
[
2
:-
2
]
# ‘ameg’
s
[
—
4
:-
2
]
# ‘eg’
s
[
:
6
]
# ‘spameg’
s
[
1
:
]
# ‘pameggs’
s
[
:
]
# ‘spameggs’
Можно задать шаг: s
=
‘spameggs’
s
[
::-
1
]
# ‘sggemaps’
s
[
3
:
5
:-
1
]
# »
s
[
2
::
2
]
# ‘aeg’
Пример:
Извлеките из строки символы с индексами кратными трем.
✍
Решение:
Задание можно выполнить, используя цикл (сложный вариант решения):
1 2
3 4
5 6 s
=
‘spameggs’
x
=
3
l
=
len
(
s
)
//
3
for
i
in
range
(
l
)
:
print
(
s
[
x:x+
1
:
3
])
# m g
x+
=
3
Для решения можно использовать просто срез:
1 2 s
=
‘spameggs’
print
(
s
[
1
::
3
])
Задание Python 5_1:
Извлеките из строки следующие срезы:
— первые восемь символов;
— четыре символа из центра строки;
— пять символов с конца строки.
Задание Python 5_2:
Дана строка длиной N. Вывести символы строки в обратном порядке.
(Не использовать цикл).
Задание Python 5_3:
Дана строка длиной N (N — четное число). Вывести символы с четными номерами в порядке возрастания их номеров: а2, а4, а6, … аn
Условный оператор не использовать.
Задание Python 5_4:
Дана строка длиной N. Вывести сначала символы с четными номерами (в порядке возрастания номеров), а затем — символы с нечетными номерами
(также в порядке возрастания номеров): а2, а4, а6,…а1, а3, а5…
Условный оператор не использовать.
Методы строк
Строки, как объекты Python, обладают методами (т.е. функциями, которые выполняют сами объекты).
join(str) —
Соединение строк из последовательности str через разделитель, заданный строкой s
=
«hello»
s1
=
«-«
join(
s
)
s1
# ‘h-e-l-l-o’
s1.count(s[, i, j]) — количество вхождений подстроки s
в строку s1
Результатом является число. Можно указать позицию начала поиска i и окончания поиска j: s1
=
«abrakadabra»
;
s1.
count(
‘ab’
)
# 2
s1.
count(
‘ab’
,
1
)
# 1
s1.
count(
‘ab’
,
1
,
—
3
)
# 0 ,
т.к. s1[1:-3]=’brakada’
s1.find(s[, i, j]) — определяется позиция первого (считая слева) вхождения подстроки s
в строку s1
. Результатом является число. i
и j
определяют начало и конец области поиска: s1
=
«abrakadabra»
;
s1.
find(
‘br’
)
# 1
s1.replace(s2,s3[, n]) — создаётся новая строка, в которой фрагмент
(подстрока) s2
исходной строки заменяется на фрагмент s3
. Необязательный аргумент n
указывает количество замен: s1
=
«breKeKeKeKs»
;
ss
=
s1.
replace(
‘Ke’
,
‘XoXo’
,
2
)
ss
# breXoXoXoXoKeKs
Задание Python 5_5:
Преобразовать дату в «компьютерном» представлении (системную дату: 2016-
03-26
) в «российский» формат, т. е. день/месяц/год (например, 26/03/2016).
Известно, что на год выделено всегда 4 цифры, а на день и месяц – всегда 2 цифры.
Примечание:
•
Использовать строковые функции языка.
•
Функциями работы с датами и временем «заведует» в Python datetime модуль, а непосредственно для работы с датами используется объект date и его методы.
Подсказка:
from
datetime
import
date
#
Получаем текущую дату
d1
=
date.
today()
# Преобразуем результат в строку
ds
=
str
(
d1
)
Задание Python 5_6:
Ввести адрес файла и «разобрать» его на части, разделенные знаком ‘/’.
Каждую часть вывести в отдельной строке.
Например: c:/изображения/2018/1.jpg
Результат: c: изображения
2018 1.jpg
Задание Python 5_7:
Ввести строку, в которой записана сумма натуральных чисел, например,
‘1+25+3’. Вычислите это выражение. Использовать строковые функции языка.
Задание Python 5_8:
Определить, является ли введённая строка палиндромом («перевёртышем») типа ABBA, kazak и пр.
Примечание: если s=’1234′
, то
S[-1]=’4′, s[-2]=’3’….
Для решения используйте алгоритм, изображенный на блок-схеме:
Самостоятельная работа:
1 вариант:
Функции:
1.
Описать функцию CircleS(R) вещественного типа, находящую площадь круга радиуса R. С помощью этой функции найти площади трех кругов с заданными радиусами. Площадь круга радиуса R вычисляется по формуле S=π
∗
R
2
. В качестве значения Пи использовать 3.14.
Процедуры:
2.
Напишите процедуру, которая выводит цифры переданного ей четырехзначного числа, кратные трем.
Списки:
3.
Создайте список, соответствующий числовому ряду, построенному по следующему принципу:
1+2+3 2+3+4 3+4+5 … 8+9+10 т.е. результат:
[6, 9, 12, 15, 18, 21, 24, 27]
2 вариант:
Функции:
1.
Описать функцию TriangleP(a, h), находящую периметр равнобедренного треугольника по его основанию a и высоте h, проведенной к основанию. С помощью этой функции найти периметры трех треугольников, для которых даны основания и высоты (периметр = сумме длин всех сторон). Для нахождения боковой стороны b треугольника использовать теорему
Пифагора: b
2
=(a/2)
2
+h
2
Процедуры:
2.
Напишите процедуру, которая выводит произведение цифр переданного ей четырехзначного числа.
Списки:
3.
Создайте список, соответствующий числовому ряду, построенному по следующему принципу:
1*3 2*4 3*5 … 8*10 т.е. результат:
[3, 8, 15, 24, 35, 48, 63, 80]
Срезы:
Общее:
4.
Дана строка. Вывести символы с нечетными номерами в порядке убывания их номеров (0-й символ тоже рассмотерть).
Например, для строки:
«Друзья!», результат: «язр»
«Друзья», результат: «язр»
Форматирование строк
Python включает форматирование строк. Данное понятие подразумевает подстановку какого-либо шаблона в определенное место (или в определенные позиции) текста.
Подстановка происходит, что называется, «на лету».
Рассмотрим пример использования в коде на Python метода format: o
Одна подстановка:
‘Hello, {}!’
format(
‘Vasya’
)
# ‘Hello, Vasya!’
Аргументом метода является текст-подстановка, который при
исполнении программы подставляется на место фигурных скобок. o
Несколько подстановок:
‘{0}{1}{0}’
format(
‘abra’
,
‘cad’
)
# ‘abracadabra’
Подстановки нумеруются, аргументы метода format заполняют
позиции для подстановок согласно их порядковым номерам,
указанным в фигурных скобках. o
другой вариант форматирования с множественными подстановками:
‘Coordinates: {latitude}, {longitude}’
format(
latitude
=
‘37.24N’
,
longitude
=
‘-115.81W’
)
‘Coordinates: 37.24N, -115.81W’
Аргументы метода format заполняются согласно указанным именам
заполнителей.
У метода format есть больше возможностей, которые выходят за рамки рассмотрения темы на данном уроке.
Задание Python 5_9:
Допустим, есть какое-то объявление и несколько разных людей, которым нужно это объявление отправить. Для этого создается заготовка с содержанием объявления, внутри которого есть ряд изменяющихся параметров: имена людей и названия событий. Вывести один вариант
итогового объявления на экран. Для задания имен и названий использовать форматирование при помощи метода format.
Используйте шаблон объявления и ориентируйтесь по цветам:
Красным
– массивы.
Коричневым
– числовая переменная.
Уважаемый (ая),
Иван Иванович
!
Приглашаем Вас на
день открытых дверей
.
Дата события:
1
мая.
С уважением, Василий.
* Примечание:
•
Вывести пять объявлений.
•
Для имен создать массив (
список
), подстановку элементов в объявление осуществлять в цикле.
•
Даты меняются от 1 до 5.
Python
ЛР 2. Часть Г. Операции
соединения и повторения.
•
Cписки — это изменяемые последовательности в отличие от строк.
•
Представим строку как объект в памяти, в этом случае, когда над строкой выполняются операции конкатенации и повторения, то сама строка не меняется, но в результате выполнения операции в другом месте памяти создается другая строка.
В строку нельзя добавить новый символ или удалить существующий, не создав при этом новой строки.
Пример:
Так, например, в Питоне нельзя переприсваивать значение для отдельных символов строки.
Программа выдаст ошибку! s
=
«aaa»
;
s
[
1
]
=
«b»
;
print
(
s1
)
Изменять строку можно только, работая с ней,
как с объектом (метод replace, например): s1
=
«breKeKeKeKs»
;
s1
=
s1.
replace(
‘Ke’
,
‘XoXo’
,
2
)
s1
# breXoXoXoXoKeKs
Что касается списков, то при выполнении операций другие списки могут не создаваться, при этом изменяется
непосредственно оригинал.
Из списков можно
удалять и добавлять новые
элементы.
•
Операция конкатенации:
[
33
,
—
12
,
‘may’
]
+
[
21
,
48.5
,
33
]
# [33, -12, ‘may’, 21, 48.5, 33]
или так: a
=
[
33
,
—
12
,
‘may’
]
b
=
[
21
,
48.5
,
33
]
print
(
a+b
)
# [33, -12, ‘may’, 21, 48.5, 33]
•
Операция повторения:
[[
0
,
0
]
,
[
0
,
1
]
,
[
1
,
1
]]
*
2
# [[0, 0], [0, 1], [1, 1], [0, 0], [0, 1], [1, 1]]
Пример:
Для списков операция переприсваивания значения отдельного элемента списка
разрешена!: a
=
[
3
,
2
,
1
]
a
[
1
]
=
0
;
print
(
a
)
# [3, 0, 1]
Можно!
Задание 6_1:
Ввести строку, в которой записана сумма натуральных чисел, например,
‘1+25+3’. Вычислите это выражение. Работать со строкой, как со списком.
Начало программы: s
=
input
(
‘
введите строку’
)
l
=
list
(
str
(
s
))
;
Другие операции над списками при помощи
функций
a
=
[
1
,
7
,
3
,
88
,
33
]
a.
sort()
#[1,3,7,33,88] —
сортировка
a.
reverse()
#[88,33,7,3,1] —
обратная сортировка
a.
index(
7
)
#2 —
индекс элемента
a.
clear()
# —
очистка списка
len
(
a
)
# —
длина списка
sum
(
a
)
# —
суммирование элементов
Функция join() — соединение элементов через определенный символ: lst
=
[
’11’
,
’22’
,
’33’
]
lst
=
«-«
join(
lst
)
# ’11-22-33′
Функция split([sep]) — возвращает список подстрок, получающихся
разбиением строки a разделителем sep: str
=
«1-2-3-4»
s1
=
str split(
«-«
)
# [‘1′,’2′,’3′,’4’]
Задание 6_2:
Дан список из 5 различных элементов. Используя функции (не использовать цикл), необходимо найти и вывести:
• минимальный и максимальный элементы списка;
• сумму и среднее арифметическое;
• второй минимальный элемент (второй по минимальности).
Начало программы: lst
=
[
4
,
5
,
2
,
3
,
4
]
Добавление и удаление элементов списка
•
Добавление элемента:
>>>
a
=
[]
>>>
a.
append(
‘444’
)
>>>
a
[
‘444’
]
Пример:
Поиск нечетных элементов в массиве mas и копирование их в массив B.
✍
Решение:
B
=
[]
for
x
in
mas:
if
x %
2
!=
0
:
B.
append(
x
)
•
Удаление элемента:
>
a.
remove(
‘444’
)
>>>
a
[]
•
Удаление элемента по индексу:
>>>
del
a
[
0
]
>>>
a
[]
При копировании списков, т.е. присваивании одного списка другому, изменение первого списка влечет за собой изменение второго списка. Так как эти объекты связаны одной областью памяти (ссылка на список). mas1
=
[
1
,
2
,
3
]
mas2
=
mas1
# создается ссылка на список
mas1
[
0
]
=
4
print
(
mas2
)
#[4, 2, 3]
Чтобы создать не ссылку на список, а копию списка можно использовать либо срез либо функцию copy.
1. mas2
=
mas1
[
:
]
# используем срез
2.
import
copy mas1
=
[
1
,
2
,
3
]
mas2
=
copy copy
(
mas1
)
Задание 6_3: Проверить, является ли заданное слово палиндромом.
Примечание:
•
Пример палиндрома: казак, ABBA
•
Использовать функции.
•
Поскольку при присваивании одного списка другому, изменение первого ведет к аналогичному изменению второго списка, то необходимо использовать копию (
copy
).
Начало программы:
import
copy stroka
=
input
(
‘введите слово’
)
lst
=
list
(
stroka
)
# конвертируем строку в список
Генерация случайных чисел
Встроенный модуль Питона random позволяет генерировать псевдослучайные числа.
Модуль random включает в себя функцию random, которая возвращает действительное число в диапазоне от 0.0 до 1.0. Каждый раз при вызове функции возвращается число из длинного ряда.
Пример:
import
random
for
i
in
range
(
10
)
: x
=
random random
()
print
(
x
)
# 0.5185207383774904 0.78283351055836 0.23601341583293534 …
Чтобы получить случайное число между 0.0 и верхней границей high, просто умножьте x на high.
Например, от 0.0 до 15.0:
import
random
for
i
in
range
(
10
)
:
x
=
random random
()
print
(
x *
15
)
# 11.075319687990554 7.152253113207329 …
Для того, чтобы получить псевдослучайное целое число:
import
random random randint(
<
начало
>,<
конец
>
)
Для того, чтобы получить псевдослучайное вещественное число:
import
random random uniform(
<
начало
>,<
конец
>
)
Еще пример:
from
random
import
randint l
=
[
randint
(
10
,
80
)
for
x
in
range
(
10
)]
Задание Python 6_4:
Найдите в массиве все простые числа и скопируйте их в новый массив.
Задание Python 6_5:
Решить задачу поиска среднего значения в списке из N элементов (вводимых в виде строк). Использовать метод добавления элементов списка и суммирования элементов
Цикл for при работе со списками
mylist
=
[
1
,
2
,
3
,
4
,
5
]
for
item
in
mylist: item
=
0
# mylist
не меняется!
print
(
mylist
)
# [1, 2, 3, 4, 5]
n
=
5
for
i
in
range
(
n
)
: mylist
[
i
]
=
0
# mylist
меняется
print
(
mylist
)
# [0, 0, 0, 0, 0]
В списке чисел проверить, все ли элементы являются уникальными, т.е. каждое число встречается только один раз
✍
Решение:
Комментарии к программе:
Решать данную задачу на языке Python мы будем «классическим» вариантом
— брать по очереди элементы списка и сравнивать каждый элемент со стоящими за ним. При первом же совпадении элементов делается вывод, что в списке есть одинаковые элементы, и работа программы завершается.
Для выхода из цикла будем использовать метод quit()
import
random m
=
6
mass
=
[]
k
=
0
j
=
0
for
i
in
range
(
m
)
: mass.
append(
random randint(
—
10
,
10
))
print
(
mass
[
i
])
# -10 0 -8 0 -10 1
for
i
in
mass: k
=
k+
1
for
j
in
range
(
k
,
m
)
:
# j = 0 -8 0 -10 -> quit
if
(
i
==
mass
[
j
])
:
# -10==0 -10==-8 -10==0 -10==-10 -> quit
print
(
‘yes’
)
quit
()
Задание Python 6_6:
Определить индексы элементов массива (списка), значения которых принадлежат заданному диапазону (т.е. не меньше заданного минимума и не больше заданного максимума)
* в результате получили индексы элементов, значения которых находятся в диапазоне [5,15]
Алгоритм:
1.
Заполнить список (массив) случайными числами
2.
Запросить для ввода минимум и максимум диапазона
3.
Найти индексы элементов, значения которых входят в диапазон. Добавлять найденные индексы к новому списку
4.
Вывести общее число найденных индексов (функция len()) и отдельно все индексы
Задание Python 6_7:
Дополнить предыдущую программу следующим:
После того, как элемент с подходящим значением добавлен в новый список – удалять его из исходного списка
* Использовать цикл while , функцию len()
Войти на сайте МЭШ
Войдите с учетной записью ученика или учителя МЭШ,
чтобы получить доступ к личному кабинету.
|
Подпрограммы: введение ПодпрограммыПодпрограмма — это отдельная часть программы, имеющая имя и решающая свою отдельную задачу. Располагается подпрограмма в начале основной программы и может быть запущена (вызвана) из основной программы по указанию имени.
Использование подпрограмм позволяет избежать дублирования кода, в случае если необходимо один и тот же код писать в разных местах программы. Каждая подпрограмма должна решать только одну задачу, либо только что-то вычислять, либо выводить какие-либо данные, либо делать что-то еще. Подпрограммы бывают двух типов — процедуры и функции. Подпрограммы-процедуры выполняют некоторые действия, например, выводят результат на экран в определенном виде (простой пример, оператор Подпрограммы-функции возвращают результат (число, символьную строчку и т.д.), который мы можем использовать в основной программе. Давайте попробуем написать простую процедуру: print("Error")
А теперь представим, что такую строчку нужно вставить во многих местах программы. Конечно, можно везде ее просто написать. Но это решение имеет два недостатка. Для таких случаев процедуры и нужны. def printError(): # описание процедуры
print("Error")
...
printError() # запуск процедуры на выполнение.
# Просто указываем имя процедуры, которую хотим выполнить
...
printError()
Надо запомнить!
Задача для тренировки:Подпрограммы: введение |
||||||||
|
Параметры и аргументы Параметры и аргументы
А теперь представим, что нам необходимо в ответ на ошибку пользователя вывести разные сообщения, в зависимости от того, какую именно ошибку он сделал. def printErrorZero():
print("Error. Division by zero!")
def printErrorInput():
print("Error in input!")
А если возможных ошибок будет намного больше? Такое решение нам не подойдет! def printError(s):
print("s")
В данной процедуре Параметр — это переменная, от значения которой зависит работа подпрограммы. Имена параметров перечисляются через запятую в заголовке подпрограммы. Теперь при вызове процедуры нужно в скобках указывать фактическое значение, которое будет присвоено параметру (переменной printError("Error! Division by zero!")
Такое значение называется аргументом. Аргумент — это значение параметра, которое передается подпрограмме при ее вызове. Аргументом может быть не только постоянное значение, но и переменная или арифметическое выражение. Задача для тренировки:Параметры и аргументы |
||||||||
|
Локальные и глобальные переменные Локальные и глобальные переменныеПеременные, которые введены в основной программе, называются глобальные (или общие). Обращаться к глобальным переменным можно из любой подпрограммы. Часто необходимо ввести дополнительные переменные, которые будут использоваться только в подпрограмме. Такие переменные называются локальными (или местными). С ними можно работать только внутри той подпрограммы, в которой они созданы. Остальные подпрограммы про них ничего не «знают». Таким образом, можно ограничить область действия (область видимости) переменной только той подпрограммой, где она действительно нужна. В программировании такой прием называется инкапсуляцией — сокрытие переменной от ее изменения извне. Проанализируйте три программы:
Задача для тренировки:Локальные и глобальные переменные |
Using try, except and raise
Since ValueError inherits from the Exception class, the first parameter when creating a ValueError object is the message it prints:
try:
int("string") #the code that raises the error
except ValueError:
raise ValueError("Your custom message here.")
This prints:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'string'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Your custom message here.
If you don’t want the previous error chain to print, put from None in the raise statement:
try:
int("string") #the code that raises the error
except ValueError:
raise ValueError("Your custom message here.") from None
This prints:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Your custom message here.
I suggest you leave the chain because it gives more information, like what was inputted that raised the error. If you want to include the information from the original error in the custom message, use the error’s attributes:
from traceback import format_tb
try:
int("string") #the code that raises the error
except ValueError as err:
raise ValueError("Custom message with traceback and original messagen" + format_tb(err.__traceback__)[0] + err.args[0] + "nEnd of error message.") from None
This prints
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Custom message with traceback and message
File "<stdin>", line 2, in <module>
invalid literal for int() with base 10: 'string'
End of error message.
Though this allows for customization of the error’s print, the code is a little unpythonic.
Using assert
Because in the question you said you wanted to block all strings, you can use assert and isinstance():
obj = "a string" #the input you want to raise the error on
assert not isinstance(obj, str), "Your custom message here."
This prints:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: Your custom message here.
Though using assert looks clean, the error won’t carry as much information because it would be a generic AssertionError. Raising a ValueError tells more information about what caused the error at a glance.
Using try, except and raise
Since ValueError inherits from the Exception class, the first parameter when creating a ValueError object is the message it prints:
try:
int("string") #the code that raises the error
except ValueError:
raise ValueError("Your custom message here.")
This prints:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'string'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Your custom message here.
If you don’t want the previous error chain to print, put from None in the raise statement:
try:
int("string") #the code that raises the error
except ValueError:
raise ValueError("Your custom message here.") from None
This prints:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Your custom message here.
I suggest you leave the chain because it gives more information, like what was inputted that raised the error. If you want to include the information from the original error in the custom message, use the error’s attributes:
from traceback import format_tb
try:
int("string") #the code that raises the error
except ValueError as err:
raise ValueError("Custom message with traceback and original messagen" + format_tb(err.__traceback__)[0] + err.args[0] + "nEnd of error message.") from None
This prints
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Custom message with traceback and message
File "<stdin>", line 2, in <module>
invalid literal for int() with base 10: 'string'
End of error message.
Though this allows for customization of the error’s print, the code is a little unpythonic.
Using assert
Because in the question you said you wanted to block all strings, you can use assert and isinstance():
obj = "a string" #the input you want to raise the error on
assert not isinstance(obj, str), "Your custom message here."
This prints:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: Your custom message here.
Though using assert looks clean, the error won’t carry as much information because it would be a generic AssertionError. Raising a ValueError tells more information about what caused the error at a glance.
В этой статье мы расскажем вам, как использовать обработчик MySQL для обработки исключений или ошибок, возникающих в хранимых процедурах.
При возникновении ошибки внутри хранимой процедуры, важно исправить ее соответствующим образом, например, продолжая или останавливая исполнение операции и выдавая сообщение об ошибке.
MySQL предоставляет простой способ определить обработчики, которые обрабатывают ошибки, исходя из общих условий, таких как предупреждения или исключения из условий, например, конкретные коды ошибок.
- Объявление обработчика
- Примеры обработки ошибок MySQL
- Пример обработчика MySQL в хранимых процедурах
- Приоритет обработчиков MySQL
- Использование проименованных условий ошибки
Чтобы объявить обработчик мы используем оператор DECLARE HANDLER:
DECLARE action HANDLER FOR condition_value statement;
Если значение условия совпадает со значением condition_value, MySQL выполнит оператор statement и продолжит или завершит текущий блок кода, исходя из значения action.
action может принимать следующие значения:
- CONTINUE: исполнение блокированного кода (BEGIN … END) продолжается;
- EXIT: выполнение блокированного кода, в котором был объявлен обработчик, завершается.
condition_value задает конкретное условие или класс условия, которые активируют обработчик.
condition_value может принимать одно из следующих значений:
- код ошибки MySQL;
- стандартное значение SQLSTATE. Или это может быть условие SQLWARNING, NOTFOUND или SQLEXCEPTION, которое является сокращением для класса значений SQLSTATE. Условие NOTFOUND используется для курсора или оператора SELECT INTO variable_list;
- название условия, связанного либо с кодом ошибки MySQL, либо со значением SQLSTATE.
В качестве statement может использоваться простой оператор или составной оператор, вшитый с помощью ключевых слов BEGIN и END.
Давайте рассмотрим несколько примеров объявления обработчиков.
Обработчик, приведенный ниже, означает: когда происходит ошибка, устанавливается значение переменной has_error 1 и выполнение продолжается:
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET has_error = 1;
Ниже приводится другой обработчик, который означает, что в случае возникновении любой ошибки, производится откат предыдущей операции, выдается сообщение об ошибке и осуществляется выход из текущего блока кода.
Если вы объявляете его внутри блока BEGIN END хранимой процедуры, он немедленно завершает хранимую процедуру:
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SELECT 'An error has occurred, operation rollbacked and the stored procedure was terminated'; END;
Если строк для вывода больше нет, для вариантов cursor или оператора SELECT INTO, значение переменной no_row_found устанавливается равным 1 и продолжается исполнение:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_row_found = 1;
При возникновении ошибки дублирования ключа, выдается ошибка MySQL 1062. Следующий обработчик выдает сообщение об ошибке и продолжает выполнение:
DECLARE CONTINUE HANDLER FOR 1062 SELECT 'Error, duplicate key occurred';
Во-первых, для демонстрации мы создаем новую таблицу с именем article_tags:
CREATE TABLE article_tags(
article_id INT,
tag_id INT,
PRIMARY KEY(article_id,tag_id)
);
В таблице article_tags хранятся связи между статьями и тегами. К каждой статье может относиться несколько тегов и наоборот.
Для простоты, мы не будем создавать таблицы articles и tags, а также внешние ключи в таблице article_tags.
Во-вторых, мы создаем хранимую процедуру, которая вставляет пару идентификаторов статьи и тега в таблицу article_tags:
DELIMITER $$
CREATE PROCEDURE insert_article_tags(IN article_id INT, IN tag_id INT)
BEGIN
DECLARE CONTINUE HANDLER FOR 1062
SELECT CONCAT('duplicate keys (',article_id,',',tag_id,') found') AS msg;
-- insert a new record into article_tags
INSERT INTO article_tags(article_id,tag_id)
VALUES(article_id,tag_id);
-- return tag count for the article
SELECT COUNT(*) FROM article_tags;
END
В-третьих, для статьи 1 мы добавляем идентификаторы тега 1, 2 и 3, с помощью вызова хранимой процедуры insert_article_tags:
CALL insert_article_tags(1,1); CALL insert_article_tags(1,2); CALL insert_article_tags(1,3);
Четвертое. Давайте попробуем вставить дубликат ключа, чтобы увидеть, действительно ли вызывается обработчик:
CALL insert_article_tags(1,3);
Мы получили сообщение об ошибке. Однако, поскольку мы объявили тип обработчика CONTINUE, хранимая процедура продолжает исполняться.
В результате, мы все равно получили список тегов для статьи:

Если мы в объявлении обработчика изменим команду CONTINUE на EXIT, мы получим только сообщение об ошибке:
DELIMITER $$
CREATE PROCEDURE insert_article_tags_2(IN article_id INT, IN tag_id INT)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
SELECT 'SQLException invoked';
DECLARE EXIT HANDLER FOR 1062
SELECT 'MySQL error code 1062 invoked';
DECLARE EXIT HANDLER FOR SQLSTATE '23000'
SELECT 'SQLSTATE 23000 invoked';
-- insert a new record into article_tags
INSERT INTO article_tags(article_id,tag_id)
VALUES(article_id,tag_id);
-- return tag count for the article
SELECT COUNT(*) FROM article_tags;
END
Теперь, мы можем попробовать добавить дубликат ключа, чтобы увидеть результат:
CALL insert_article_tags_2(1,3);

В случае если у вас есть несколько обработчиков, которые имеют право обрабатывать ошибку, MySQL для обработки ошибки будет вызывать наиболее подходящий обработчик.
Ошибка всегда обозначается одним из кодов ошибки MySQL, так что MySQL в этом плане имеет возможность четко их идентифицировать.
Обозначения SQLSTATE для многих кодов ошибок MySQL менее специфичны. SQLEXCPETION или SQLWARNING представляют собой сокращения класса значений SQLSTATES, поэтому они имеют общий характер.
На основании правил приоритета обработчиков обработчик кода ошибки MySQL, обработчик SQLSTATE и обработчик SQLEXCEPTION имеют приоритеты один, два и три соответственно.
Предположим, что в хранимой процедуре insert_article_tags_3 мы объявляем три обработчика:
DELIMITER $$
CREATE PROCEDURE insert_article_tags_3(IN article_id INT, IN tag_id INT)
BEGIN
DECLARE EXIT HANDLER FOR 1062 SELECT 'Duplicate keys error encountered';
DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT 'SQLException encountered';
DECLARE EXIT HANDLER FOR SQLSTATE '23000' SELECT 'SQLSTATE 23000';
-- insert a new record into article_tags
INSERT INTO article_tags(article_id,tag_id)
VALUES(article_id,tag_id);
-- return tag count for the article
SELECT COUNT(*) FROM article_tags;
END
Теперь мы пробуем добавить в таблицу article_tags дубликат ключа через вызов хранимой процедуры:
CALL insert_article_tags_3(1,3);
Как видите, вызывается обработчик кода ошибки MySQL:

Начинаем с объявления обработчика ошибки:
DECLARE EXIT HANDLER FOR 1051 SELECT 'Please create table abc first'; SELECT * FROM abc;
Что означает код 1051? Представьте, что у вас есть большая хранимая процедура, по всему коду которой разбросаны некорректные значения. Настоящий кошмар для разработчиков обслуживания.
К счастью, MySQL предоставляет нам оператор DECLARE CONDITION, который объявляет проименованное условие ошибки, связанное с условием.
Синтаксис оператора DECLARE CONDITION выглядит следующим образом:
DECLARE condition_name CONDITION FOR condition_value;
condition_value может представлять собой код ошибки MySQL, например 1015, или значение SQLSTATE. condition_value представляется с помощью condition_name.
После объявления вы можете обращаться к condition_name вместо condition_value.
Таким образом, мы можем переписать код, приведенный выше, следующим образом:
DECLARE table_not_found CONDITION for 1051; DECLARE EXIT HANDLER FOR table_not_found SELECT 'Please create table abc first'; SELECT * FROM abc;
Этот код, очевидно, более удобен для чтения, нежели предыдущий. Отметим, что объявление условия должно размещаться перед объявлением обработчика или объявлением курсора.
Исключения и взаимодействие с API
На текущий момент мы уже знаем достаточно многое из основ ООП. Однако созда-ние приложений под Windows в среде Delphi не ограничивается применением объ-ектно-ориентированного подхода. В частности, иногда возникают такие ситуации, что приходится обращаться к функциям Windows API напрямую. Кроме того, нам следует рассмотреть обработку ошибок в программах, а так же осветить вопрос некоторых глобальных объектов.
Исключения и их классы
Исключительные ситуации, или исключения (exception) могут возникать по ходу выполнения программы ввиду целого ряда причин. Они могут быть вызваны как ошибками в коде программы (например, при попытке обратиться к объекту, который не был предварительно создан), при вводе пользователем неожидаемых значений (например, строки, которая не может быть приведена к числу), при ошибках работы оборудования и т.д. Любая программа, претендующая на качественную разработку, должна уметь обрабатывать все подобные исключительные ситуации.
При возникновении подобных ошибок в программах, созданных при помощи Delphi, автоматически создается объект — Exception. Класс Exception является базовым для ряда других классов исключений — EMathError, EInvalidOp, EZeroDivide и т.д. (названия всех классов, относящиеся к исключениям, принято начинать не с буквы T, а с буквы E). Он происходит непосредственно от класса TObject и имеет 2 свойства — Message и HelpContext, а так же 8 методов.
Свойство Message имеет тип string и содержит описание исключения. При возникновении ошибки этот текст используется в окне сообщения. Ас войство HelpContext определяет индекс раздела справочного файла, содержащего информацию об ошибке. Если значение этого свойства равно нулю, то оно будет ссылаться на раздел справки родительского объекта.
Что касается методов, то все они представлены различными вариантами метода Create. Сам метод Create для исключений определен следующим образом:
constructor Create(const Msg: string);
Т.е., фактически, создавая исключение, следует сразу же назначить значение его свойству Message при помощи аргумента конструктора. Другой вариант конструктора, CreateHelp, позволяет параллельно назначить значение и для второго свойства:
constructor CreateHelp(const Msg: string; AHelpContext: Integer);
Если в тексте сообщения следует привести какие-либо динамически получаемые данные, то используют вариант конструктора с суффиксом Fmt:
constructor CreateFmt(const Msg: string; const Args: array of const);
constructor CreateFmtHelp (const Msg: string; const Args: array of const; AHelpContext: Integer);
При этом значения, указанные в массиве Args, будут подставлены в строку. Для этого используется функция Format, которой передаются строка и массив в качестве аргументов. Эта функция выполняет подстановку значений массива в места строки, выделенные при помощи символа %. Например, если строка выглядит как «Ошибка в функции %s», а массив определен как «[‘MyFunc’]», то результатом выполнения этой функции будет «Ошибка в функции MyFunc». Соответственно, создание подобного исключения будет выглядеть следующим образом:
constructor CreateFmt('Ошибка в функции %s', ['MyFunc']);
Как уже было отмечено, класс Exception имеет ряд потомков, каждый из которых предназначен для обработки того или иного типа ошибок. Например, для математических ошибок определен класс EMathError. Однако этот класс сам по себе не используется, зато его потомки, среди которых отметим классы EInvalidOp, EOverflow, EZeroDivide, используются для оповещения о таких ситуациях, как неверная операция, переполнение буфера и попытка деления на 0, соответственно.
При возникновении исключительной ситуации создается исключение того или иного вида, на основании чего можно определить, в чем именно кроется проблема.
Вызвать исключение в программе можно и искусственным методом — при помощи ключевого слова raise. Например программа может проверять какой-либо ввод пользователя, и в том случае, если он оказывается не тем, что ожидалось, генерировать исключительную ситуацию:
if password <> 'password' then raise Exception.Create('Неверный пароль!');
Выполнение оператора, указанного после raise, приводит к возникновению исключительной ситуации. После этого дальнейшее выполнение кода процедуры прерывается, равно как и кода, вызвавшего эту процедуру, если вызов был произведен из другой подпрограммы. Перемещение исключения можно рассматривать с точки зрения всплытия, т.е. с места своего возникновения ошибка последовательно «всплывает» сначала к вызвавшей данную процедуру или функцию подпрограмме, от нее — к следующей и т.д., пока не дойдет до уровня выполнения программы, т.е. до глобального объекта Application. На этом, конечном этапе и будет выдано сообщение об ошибке.
ПРИМЕЧАНИЕ
С некоторыми глобальными объектами, в том числе с Application, мы ознакомимся несколько позже в этой же главе.
Если при этом ошибка возникла в основном коде программы (т.е. вызвавший ошибку код был написан в самом файле проекта dpr), то на этом выполнение программы прекратится, о чем будет выдано сообщение (рис. 10.1).

Рис. 10.1. Ошибка приложения
В том же случае, если исключительная ситуация произошла в каком-либо модуле, то программа продолжит свою работу, ожидая дальнейших действий пользователя. Однако некоторые данные при этом могут оказаться утерянными (например, функция не вернет значения), или же может оказаться невыполненным какой-либо иной важный код, скажем, создающий глобальные объекты, сохраняющий информацию и т.д. Все это говорит о том, что исключительные ситуации следует обрабатывать.
Обработка исключений
Для обработки исключительных ситуаций в Delphi используются специальные операторы — try…except и try…finally. Эти операторы являются своего рода ловушками для исключительных ситуаций и позволяют разработчику приложения предусмотреть код, обрабатывающий возникшие исключения. Тем самым можно на любом этапе перехватить дальнейшее всплытие ошибки.
При помощи оператора try…except выполняет перехват ошибки, как правило, с целью ее подавления. Он имеет следующий синтаксис:
try
<потенциально вызывающий исключения код>
except
[ on <Класс исключения> do <оператор>; ]
end;
В том случае, если между except и end не писать никакого кода, то исключительная ситуация будет просто подавлена. Однако такое подавление чаще всего не является достаточным условием, поскольку оно не несет никакой информации ни пользователю, ни самой программе. Например, если так подавить ошибку с неверным паролем (а из-за подавления никакого сообщения выдано не будет), то пользователь такой программы может лишь догадываться, почему после того, как он сообщил пароль, ничего не происходит. В данном случае было бы правильным все-таки сообщить о том, что пароль введен не верно. Для этого используют вложенную секцию on…do:
try
if password <> 'password' then raise Exception.Create('Неверный пароль!');
except
on E: Exception do ShowMessage(E.Message);
end;
На сей раз в случае возникновения исключения пользователь получит уведомление о том, что же произошло. Для этого мы создали объект E, которому автоматически присваивается значение ошибки, и использовали его для вывода информации о ней. Дальнейшее выполнение программы в данном случае будет продолжено, поскольку после окончания блока try…end исключение более не существует.
На самом деле, использование такого объекта может быть необязательным, если детальная информация об ошибке не представляется необходимой. В таком случае можно использовать следующий блок обработки исключения:
try
if password <> 'password' then raise Exception.Create('Неверный пароль!');
except
on Exception do ShowMessage('ОШИБКА!');
end;
Что касается блоков обработки, то их может быть несколько, каждый — для своего класса исключения:
try
a:=b*c/d;
except
on EZeroDivide do ShowMessage('Делить на 0 нельзя');
on EOverflow do ShowMessage('Слишком большое число');
on EMathError do ShowMessage('Математическая ошибка');;
end;
Здесь мы определили 3 блока, и в случае возникновения той или иной исключительной ситуации, будет выдано то или иное сообщение. Этим данная часть оператора напоминает оператор case, для которого, как мы помним, существовал вариант «для остальных случаев» — else. Имеется такая возможность и здесь:
try
a:=b*c/d;
except
on EZeroDivide do ShowMessage('Делить на 0 нельзя');
on EOverflow do ShowMessage('Слишком большое число');
on EMathError do ShowMessage('Математическая ошибка');
else
ShowMessage('Общая ошибка');
end;
Наконец, если тип ошибки не имеет никакого значения, то можно оставить только общий обработчик, для чего не требуется даже ключевого слова else:
try
a:=b*c/d;
except
ShowMessage('Общая ошибка');
end;
Важно лишь отметить, что все эти блоки выполняются только тогда, когда возникает исключительная ситуация. При этом, если после ключевого слова try расположено несколько операторов, и исключение возникает в одном из них, то все последующие выполнены не будут. Вместе с тем, случаются ситуации, когда имеется код, который следует выполнить в любом случае, без оглядки на то, что случится перед этим. В таких случаях используют другой оператор - try…finally, и требующий обязательного выполнения код помещают в часть после finally. Типичным примером использования такой конструкции можно считать уничтожение объектов или иные операции освобождения памяти, а так же закрытия файлов и т.д. Например, при работе с файлами всегда следует использовать try…finally для закрытия файла:
try
Rewrite(F);
writeln(F,s);
finally
CloseFile(F);
end;
В данном случае, если даже произойдет ошибка, связанная с доступом к файлу — т.е. если его не удастся открыть (например, если диск защищен от записи), или же записать в него информацию (нет места на диске), закрыт он будет в любом случае, что предотвратит возможные дальнейшие ошибки. При этом само исключение подавлено не будет, т.е. сообщение об ошибке будет выведено и дальнейшее выполнение подпрограммы (но уже после блока finally…end) будет прервано.
Но оба подхода можно комбинировать. Например, в данном случае блок try…finally можно вложить в блок try…except:
try
AssignFile(F);
try
Rewrite(F);
writeln(F,s);
finally
CloseFile(F);
end;
except
on E: Exception do ShowMessage(E.Message);
end;
Кроме этого, в Delphi допускается вкладывать однотипные обработчики ошибок друг в друга, например, один блок try…except может быть вложен в другой.
Глобальные объекты
При создании Windows-приложений нередко возникает необходимость в управлении программой в целом как отдельным объектом. Для этих целей в Delphi предусмотрен специальный объект — Application класса TApplication, представляющий программу в целом. Его использование можно увидеть в любом файле проекта VCL-приложения. Чтобы увидеть это, достаточно создать новое приложение и открыть файл проекта, для откытия которого можно воспользоваться списком модулей, вызываемого кнопкой View Unit (можно так же через главное меню — View ‘ Units, или при помощи сочетания горячих клавиш Ctrl+F12). По умолчанию он имеет название Project1, и его стандартный код имеет вид, приведенный в листинге 10.1.
Листинг 10.1. Заготовка кода для VCL-приложения
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Уже по приведенному в листинге коду мы можем познакомиться с 3 основными методами этого объекта — Initialize, CreateForm и Run. Первый производит подготовительную работу, т.е. фактически, создает объект приложения. Метод CreateForm используется для создания окон приложения, а метод Run производит фактический запуск программы на выполнение. Среди других методов приложения моно отметить такие, как Minimize и Restore, служащие, соответственно, для сворачивания программы на панель задач и для ее восстановления, а так же метод BringToFront, который выводит окно на верхнюю поверхность рабочего стола. Метод Terminate используется для прекращения работы программы (он вызывается автоматически, когда закрывается главное окно приложения). Еще 4 метода — HelpCommand, HelpContext, HelpJump и HelpKeyword — предназначены для работы со справочными файлами.
При работе приложения, в случае обработки больших массивов данных, возникают случаи, когда программа не только не реагирует на действия пользователя, но даже не может выполнить обновление собственного окна. Для того, чтобы предотвратить подобные ситуации, используют специальный метод — ProcessMessages, который предписывает приложению обработать накопившуюся очередь сообщений.
Среди свойств приложения, прежде всего, следует отметить такие, как Title, Icon и HelpFile. Свойство Title определяет заголовок программы, т.е. то, что вы видите на панели задач. Свойство Icon определяет значок («иконку») программы. Ну а свойство HelpFile связывает приложение с файлом справочной информации. Все эти свойства можно определить как программно, написав соответствующий код, так и при помощи окна свойств проекта (Project > Options), на закладке Application (рис. 10.2).

Рис. 10.2. Установка параметров приложения в окне свойств проекта
Если установить в диалоге Project Options новые значения и нажать на кнопку OK, то внесенные изменения для свойств Title и HelpFile отобразятся в коде программы. Что касается значка программы, то он хранится в отдельном файле ресурсов (res), который присоединяется к приложению в процессе компиляции, для чего используется директива «{$R *.res}».
Поскольку любой визуальный компонент может отображать всплывающую текстовую подсказку, то для объекта Application предусмотрен ряд свойств, управляющих видом и выводом таких подсказок. В частности, цвет определяют при помощи свойства HintColor, задержку перед появлением после наведения на компонент мышки — при помощи HintPause, а время его отображения — свойством HintHidePause.
Некоторые свойства приложения доступны только во время выполнения. Среди них можно выделить свойство ExeName, содержащее информацию об имени самого исполняемого файла, включая полный путь к нему.
Помимо Application, при запуске приложения создается еще один глобальный объект, представляющий экранную среду — Screen. При помощи этого объекта можно получить информацию о разрешение экрана, установить вид курсора мыши для приложения, или узнать количество его окон. Основные свойства класса TScreen приведены в таблице 10.1.
| Свойство | Тип | Описание |
|---|---|---|
| ActiveControl | TWinControl | Указывает, какой элемент управления в данный момент имеет фокус ввода |
| ActiveForm | TForm | Указывает, какое окно активно в данный момент |
| Cursor | TCursor | Определяет вид указателя курсора мышки для приложения |
| Cursors | array of HCursor | Список всех курсоров, доступных для приложения |
| Fonts | TStrings | Список названий всех шрифтов, доступных для вывода на экран |
| FormCount | Integer | Указывает на число окон (форм), созданных приложением |
| Forms | array of TForm | Список всех окон, созданных приложением |
| Height | Integer | Указывает на вертикальное разрешение экрана |
| HintFont | TFont | Определяет шрифт для всплывающих подсказок |
| IconFont | TFont | Определяет шрифт для подписей к значкам в диалогах выбора файлов |
| MenuFont | TFont | Определяет шрифт для меню |
| Width | Integer | Указывает на горизонтальное разрешение экрана |
| WorkAreaHeight | Integer | Указывает на высоту рабочего стола Windows |
| WorkAreaLeft | Integer | Указывает на координаты левого угла рабочего стола |
| WorkAreaRect | Integer | Указывает на координаты прямоугольника, образующего рабочий стол |
| WorkAreaTop | Integer | Указывает на координаты верхнего угла рабочего стола |
| WorkAreaWidth | Integer | Указывает на ширину рабочего стола |
Использовать объекты Screen и Application можно как в главном модуле программы (файле проекта), так и в модулях отдельных форм. При использовании в главном мо-дуле обычно устанавливают глобальные параметры, например, вид всплывающих подсказок. В частности, можно определить довольно-таки экзотический вид всплы-вающих подсказок, дополнив программу следующими строками:
Screen.HintFont.Color:=$00408080; // цвет шрифта
Screen.HintFont.Size:=14; // размер шрифта
Application.HintColor:=$0080FF80; // цвет фона
Application.HintPause:=1000; // задержка перед появлением 1 секунда
Application.HintHidePause:=2000; // время показа 2 секунды
Если вставить этот код в dpr-файл перед обращением к методу Application.Run, то можно будет убедиться, что через секунду после наведения курсора на окно запу-щенного приложения будет появляться всплывающая подсказка с крупным коричне-вым текстом на зеленом фоне. Разумеется, при этом для окна приложения следует установить значения свойства ShowHint в true, и написать какой-либо текст для свой-ства Hint. Впрочем, это можно сделать не только через инспектор объекта в процессе разработки приложения, но и программно, поместив соответствующий код после создания формы. В результате мы получим код, приведенный в листинге 10.2.
Листинг 10.2. Использование объектов Application и Screen
program app_scr;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Form1.Hint:='Ну и подсказочка!';
Form1.ShowHint:=true;
Screen.HintFont.Color:=$00408080;
Screen.HintFont.Size:=14;
Application.HintColor:=$0080FF80;
Application.HintPause:=1000;
Application.HintHidePause:=2000;
Application.Run;
end.
Здесь же можно установить и такие параметры, как заголовок программы, используя свойство Title объекта Application:
Application.Title:='Super Hint!';
Кроме того, можно поэкспериментировать с такими свойствами объекта Screen, как Height и WorkAreaHeight, причем для вывода информации можно использовать заго-ловок главного окна:
Form1.Caption:='Экран '+IntToStr(Screen.Height)+', рабочий стол '+ IntToStr(Screen.WorkAreaHeight);
В данном случае в строку Uses потребуется дописать модуль SysUtils, поскольку ис-пользованная здесь функция IntToStr расположена именно в этом модуле. Оконча-тельный вариант программы можно найти в каталоге DemoPart2Global.
Работа с INI-файлами
При разработке приложений часто встает вопрос о том, где и как хранить информа-цию, связанную с его настройками. Нередко для этих целей используются специаль-ные INI-файлы, которые хранят в себе информацию, разбитую по логическим груп-пам в виде «ключ-значение». В Delphi имеется класс, обеспечивающий простую ра-боту с такими файлами — TIniFile. Чтобы приложение могло получить доступ к этому классу, в секцию используемых модулей следует добавить inifiles.
Имя файла, ассоциированного с объектом типа TIniFile, задается непосредственно при создании экземпляра этого класса, в конструкторе Create:
var MyIni: TIniFile;
...
TIniFile.Create('myfile.ini');
Впоследствии можно узнать, какой файл ассоциирован с данным объектом при по-мощи его свойства FileName, однако изменить его уже не получится. Вместе с тем, у TIniFile имеется свыше 20 методов, при помощи которых можно считывать, прове-рять и изменять содержимое INI-файла. Все они приведены в таблице 10.2.
| Метод | Принимаемые параметры | Описание |
|---|---|---|
| DeleteKey | const Section, Ident: String | Удаляет указанный ключ из INI файла |
| EraseSection | const Section: String | Удаляет содержимое указанной секции в INI файле |
| ReadSection | const Section: String; Strings: TStrings | Считывает имена всех ключей в указанной секции и заносит их в список строк |
| ReadSections | Strings: TStrings | Считывает названия всех секций в файле и заносит их в список строк |
| ReadSectionValues | const Section: String; Strings: TStrings | Считывает все значения в указанной секции и заносит их в список строк |
| ReadString | const Section, Ident, Default: String | Считывает и возвращает значение-строку из указанного ключа |
| WriteString | const Section, Ident, Value: String | Записывает значение-строку в указанный ключ |
| ReadBool | const Section, Ident: String; Default: Boolean | Считывает и возвращает булево значение из указанного ключа |
| ReadDate | const Section, Ident: String; Default: TDateTime | Считывает и возвращает значение-дату из указанного ключа |
| ReadDateTime | const Section, Ident: String; Default: TDateTime | Считывает и возвращает значение-дату и время из указанного ключа |
| ReadFloat | const Section, Ident: String; Default: Double | Считывает и возвращает значение-вещественное число из указанного ключа |
| ReadInteger | const Section, Ident: String; Default: Longint | Считывает и возвращает значение-целое число из указанного ключа |
| ReadTime | const Section, Ident: String; Default: TDateTime | Считывает и возвращает значение-время из указанного ключа |
| SectionExists | const Section: String | Проверяет INI файл на наличие указанной секции |
| WriteBool | const Section, Ident: String; Value: Boolean | Записывает булево значение в указанный ключ |
| WriteDate | const Section, Ident: String; Value: TDateTime | Записывает значение-дату в указанный ключ |
| WriteDateTime | const Section, Ident: String; Value: TDateTime | Записывает значение-дату и время в указанный ключ |
| WriteFloat | const Section, Ident: String; Value: Double | Записывает значение-вещественное число в указанный ключ |
| WriteInteger | const Section, Ident: String; Value: Longint | Записывает значение-целое в указанный ключ |
| WriteTime | const Section, Ident: String; Value: TDateTime | Записывает значение-время в указанный ключ |
| ValueExists | const Section, Ident: String | Проверяет INI файл на наличие указанного ключа в определенной секции |
Таким образом, можно без каких-либо дополнительных накладных расходов (с точки зрения написания собственного кода), создавать и считывать стандартные INI-файлы. Например, мы можем создать приложение, которое сможет «запоминать» введенную информацию и отображать ее при следующем запуске. В принципе, мы уже делали нечто подобное еще при создании программы «угадывания чисел», рассмотренной в первой части. Однако тогда мы лишь последовательно записывали в файл пару строк, а затем таким же образом их считывали. Но если бы нам требовалось сохранить большее количество значений, то мы столкнулись бы с трудностями такого рода, как невозможность идентифицировать то или иное значение при просмотре файла. Кроме того, пришлось бы постоянно держать в уме, какая по строка что должна хранить. Использование INI-файлов решает эту задачу.
Для примера возьмем консольное приложение, которое будет последовательно спрашивать различную информацию у пользователя, а затем сохранит ее в указанном файле. При следующем запуске она сможет считать этот файл и вывести информацию из него на экран. Основное тело программы при этом может получиться примерно таким, как показано в листинге 10.3.
Листинг 10.3. Название листинга
program myini;
{$APPTYPE CONSOLE}
uses
SysUtils, IniFiles;
var
ans: Char;
fn: string;
begin
write('Load data from an INI file? [Y/N]');
readln(ans);
if (ans='Y') or (ans='y') then begin
write('Please input file name: ');
readln(fn);
fn:='c:'+fn+'.ini';
if FileExists(fn) then begin
ShowData(fn);
end else begin
writeln('File not found and will be created.');
FillData(fn);
end;
end else begin
write('Please input file name to save data: ');
readln(fn);
fn:='c:'+fn+'.ini';
FillData(fn);
end;
readln(fn);
end.
Прежде всего, наша программа интересуется, хочет ли пользователь просмотреть информацию из уже существующего файла, или нет, и если хочет, то запрашивает имя файла. Здесь мы подразумеваем, что пользователь будет вводить только имя файла, без пути и расширения, которые добавляются автоматически. Затем стандартная функция FileExists проверяет получившийся файл на существование, после чего либо выводит его содержимое при помощи процедуры ShowDate (которую нам еще предстоит создать), либо выводит сообщение о том, что файл не найден, но будет создан. После этого программа обращается к процедуре FillData, которая так же будет нами написана для ввода информации и сохранения ее в INI-файле. Эта же функция будет вызвана и в том случае, если пользователь изначально откажется от вывода информации, в таком случае программа предварительно запросит имя файла для дальнейшего сохранения.
Теперь, когда основа программы готова, можно определиться, какие данные мы хотим хранить, и какой для этого понадобится формат файла. Допустим, мы хотим сохранить информацию 2-х категорий: персональную и рабочую. В таком случае наш INI файл будет состоять из 2 секций, скажем, Userdata и Jobdata. В первой секции сохраним имя (Name) и возраст (Age), а во второй — должность (Title) и оклад (Salary). Процедура, отвечающая за вывод информации, получится достаточно простой — в ней достаточно создать INI-файл с указанным именем и последовательно считывать информацию, попутно выводя ее на экран. Например, для строкового значения мы получим следующий код:
writeln('Name...... '+IniF.ReadString('Userdata','Name','Anonymous'));
Если же речь идет о числовом значении, то нам придется предварительно преобразовать его в строку:
writeln('Age....... '+IntToStr(IniF.ReadInteger('Userdata','Age',0)));
Несколько сложнее получится код процедуры для записи файла, что, впрочем, связано не с самой записью данных, а в том, что их предварительно следует получить от пользователя. Поэтому там, где мы при выводе обходились одной строкой кода, для ввода понадобится целых 3, а так же переменная для хранения вводимого значения:
write('Name: ');
readln(s);
IniF.WriteString('Userdata','Name',s);
Подобный код потребуется выполнить для каждого поля данных, при этом нам понадобятся 3 различных переменных для хранения данных 3 типов (дважды — строк, и по разу целое и вещественное числа). Предварительно следует не забыть создать переменную типа TIniFile, и вывести пояснительный текст, а к завершению работы процедуры освободить память, занимаемую более не нужной переменной. Последнее условие следует выполнить и в процедуре ShowData. В итоге мы получим код, приведенный в листинге 10.4.
Листинг 10.4. Процедуры сохранения и считывания INI-файлов
procedure FillData(fn: string);
var
IniF: TIniFile;
s: string;
i: integer;
f: double;
begin
IniF:=TIniFile.Create(fn);
writeln('Please fill a form...');
write('Name: ');
readln(s);
IniF.WriteString('Userdata','Name',s);
write('Age: ');
readln(i);
IniF.WriteInteger('Userdata','Age',i);
write('Position: ');
readln(s);
IniF.WriteString('Jobdata','Title',s);
write('Salary: ');
readln(f);
IniF.WriteFloat('Jobdata','Salary',f);
IniF.Free;
end;
procedure ShowData(fn: string);
var
IniF: TIniFile;
begin
IniF:=TIniFile.Create(fn);
writeln('Name...... '+IniF.ReadString('Userdata','Name','Anonymous'));
writeln('Age....... '+IntToStr(IniF.ReadInteger('Userdata','Age',0)));
writeln('Position.. '+IniF.ReadString('Jobdata','Title','Unemployed'));
writeln('Salary.... '+FloatToStrF(IniF.ReadFloat('Jobdata','Salary',0.00),ffFixed,6,2));
IniF.Free;
end;
С полным исходным кодом программы можно ознакомиться в примере, расположенном в каталоге DemoPart2IniFiles.
Работа с реестром Windows
Файлы INI и класс TIniFiles — достаточно удобный способ хранения различной настроечной информации. Тем не менее, начиная с Windows 95, появилось централизованное хранилище для настроек системы и всех установленных программ — реестр (Registry). При разработке приложений в Delphi удобнее всего работать с реестром, используя класс TRegistry. Чтобы включить объявление этого класса, следует указать модуль registry в списке uses.
Реестр Windows имеет несколько ключевых разделов, в чем можно убедиться, открыв имеющуюся в Windows программу редактирования реестра (regedit). В частности это разделы HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_USERS, HKEY_LOCAL_MACHINE и HKEY_CURRENT_CONFIG. Чтобы приступить к работе с реестром из программы, требуется указать один из разделов. Делается это при помощи свойства RootKey:
var Reg: TRegistry;
...
Reg:=TRegistry.Create;
Reg.RootKey:=HKEY_CURRENT_USER;
Далее в ход идут методы класса TRegistry. В частности, за выбор раздела реестра, из которого надо будет считывать данные, используется метод OpenKeyReadOnly. В качестве аргумента ему передается адрес раздела реестра, например:
Reg.OpenKeyReadOnly('SOFTWAREMySoftTestApp');
Если указанный раздел существует, и к нему может быть обеспечен доступ, то обращение к данному методу вернет истину. Если же раздела может не существовать, или если требуется открыть раздел на запись, то используют метод OpenKey:
Reg.OpenKey('SOFTWAREMySoftTestApp',true);
Для него в качестве 2-го параметра указывают булево значение, которое указывает на то, должен ли указанный раздел быть создан, если его не существует. В результате выполнения приведенного кода раздел, при необходимости, будет создан и открыть на чтение и запись. Если же требуется только создать новый раздел, то используют метод CreateKey:
Reg.CreateKey('SOFTWAREMySoftTestApp');
Для удаления раздела используют метод DeleteKey, а для проверки указанного раздела на существование — KeyExists. Подобно методу CreateKey, эти методы так же принимают адрес раздела и возвращают ложь или истину в зависимости от результата операции.
Если же требуется выполнить проверку на наличие значения в текущем открытом разделе, то используют метод ValueExists, которому в качестве аргумента передают имя значения.
Что касается записи и считывания значений, то, подобно классу TIniFile, для TRegistry определен ряд методов для взаимодействия с данными различных типов, причем для реестра к типам Boolean, String, Double, Integer и даты-времени, добавляется еще и Currency. Соответственно, мы имеем 8 пар методов для этих целей.
Для примера рассмотрим приложение, состоящее из единственного окна, которое будет «запоминать» свои размеры и расположение на экране. Для этого создадим новое VCL-приложение (File ‘ New ‘ Application), щелкнем сначала по его форме (Form1), а затем — по окну инспектора объекта (Object Inspector). В нем выберем закладку Events (события), найдем событие OnClose и дважды щелкнем по строке напротив. В результате мы получим заготовку для процедуры TForm1.FormClose, в которую нам надо будет добавить объявление переменной для реестра:
var
Reg: TRegistry;
Затем в теле функции напишем следующие строки:
Reg:=TRegistry.Create;
Reg.RootKey:=HKEY_CURRENT_USER;
Reg.OpenKey('SOFTWAREMySoftTestApp',true);
Reg.WriteInteger('left',Form1.Left);
Reg.WriteInteger('top',Form1.Top);
Reg.WriteInteger('height',Form1.Height);
Reg.WriteInteger('width',Form1.Width);
Reg.Free;
Вначале мы создаем экземпляр класса, затем выбираем корневой раздел, после чего открываем ключ на запись (он будет создан при необходимости), и последовательно заносим в него пространственные координаты окна. В завершение работы этой процедуры мы экземпляр класса удаляется из памяти за ненадобностью.
Теперь рассмотрим считывание из реестра, для чего создадим процедуру, обрабатывающую событие создания окна, для чего в инспекторе объекта найдем событие OnCreate и сделаем двойной щелчок напротив него. В получившейся процедуре нам так же понадобится сначала объявить переменную Reg, затем создать экземпляр класса и установить корневой раздел. Затем следует открыть раздел на чтение, причем если это окажется невозможным (а при первом запуске так и будет, поскольку раздел будет создан только после выхода из программы), то считывать ничего не потребуется. Поэтому задействуем условный оператор:
if Reg.OpenKeyReadOnly('SOFTWAREMySoftTestApp') then begin
...
end;
После этого остается считать все нужные данные из реестра, присваивая хранящиеся в них значения соответствующим свойствам Form1. Например, для высоты и ширины мы получим:
Form1.Height:=Reg.ReadInteger('height');
Form1.Width:=Reg.ReadInteger('width');
Вместе с тем, было бы полезным все-таки проверять наличие запрашиваемых значений в реестре, чтобы избежать возникновения исключительных ситуаций. Для этого всякий раз надо будет проверять ключ на существование:
if Reg.ValueExists('width') then Form1.Width:=Reg.ReadInteger('width');
В результате код этого модуля программы получит приблизительно такой вид, как показано в листинге 10.5.
Листинг 10.5. Сохранение координат и размеров окна в реестре
unit Unit1;
interface
uses
Windows, Forms, Registry;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
Reg: TRegistry;
begin
Reg:=TRegistry.Create;
Reg.RootKey:=HKEY_CURRENT_USER;
if Reg.OpenKeyReadOnly('SOFTWAREMySoftTestApp') then begin
if Reg.ValueExists('left') then
Form1.Left:=Reg.ReadInteger('left');
if Reg.ValueExists('top') then
Form1.Top:=Reg.ReadInteger('top');
if Reg.ValueExists('height') then
Form1.Height:=Reg.ReadInteger('height');
if Reg.ValueExists('width') then
Form1.Width:=Reg.ReadInteger('width');
end;
Reg.Free;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
Reg: TRegistry;
begin
Reg:=TRegistry.Create;
Reg.RootKey:=HKEY_CURRENT_USER;
Reg.OpenKey('SOFTWAREMySoftTestApp',true);
Reg.WriteInteger('left',Form1.Left);
Reg.WriteInteger('top',Form1.Top);
Reg.WriteInteger('height',Form1.Height);
Reg.WriteInteger('width',Form1.Width);
Reg.Free;
end;
end.
С исходным кодом приложения так же можно ознакомится, посмотрев его в каталоге DemoPart2Registry.
Процедуры и функции стандартных диалогов
В Delphi предусмотрено несколько процедур и функций, предназначенных для вывода простых диалоговых окон. В частности, процедура ShowMessage и функция MessageDlg позволяют вывести сообщение, а функции InputBox и InputQuery отображают окно для ввода информации.
Простейшим вариантом вывода сообщения является использование процедуры ShowMessage. Она отображает переданную ей в качестве аргумента строку на простом диалоговом окне с единственной кнопкой OK. Типичный пример использования этой процедуры — информирование пользователя о выполнении той или иной части программы:
ShowMessage('Формат диска C: завершен');
Кроме самой процедуры ShowMessage, имеются 2 других варианта — ShowMessagePos и ShowMessageFmt. Первый позволяет вывести диалоговое окно в определенном месте, что достигается путем указания координат по горизонтали и вертикали:
ShowMessagePos('Формат диска C: завершен',100,200);
Второй позволяет вывести отформатированную строку, используя обращение к функции Format, как и в случае с конструктором исключений. Таким образом, для вывода сообщения с переменной частью предпочтительно использовать именно этот вариант процедуры:
ShowMessageFmt('Формат диска %s завершен',['C:']);
Все варианты процедуры ShowMessage выводят окно с единственной кнопкой OK, при этом, разумеется, никакого значения не возвращается. В том же случае, если сообщение выводится для того, чтобы запросить у пользователя подтверждения на то или иное действие, то нам, во-первых, потребуется функция — чтобы получить вариант ответа, а так же возможность указать возможные варианты. Все это мы имеем в лице функции MessageDlg, которая имеет следующее определение:
function MessageDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Word;
Здесь сразу же требуется прояснить 2 момента: тип диалога и тип кнопок. За тип диалога отвкечает 2-й параметр, который имеет тип TMsgDlgType и может принимать одно из следующих значений:
- mtWarning — диалог типа «предупреждение», имеет заголовок «Warning» и рисунок, изображающий восклицательный знак на фоне желтого треугольника;
- mtError — диалог типа «ошибка», имеет заголовок «Error» и изображение косого креста в красном круге;
- mtInformation — диалог типа «информация», имеет заголовок «Information» и значок со стилизованной буквой «i» в синих тонах;
- mtConfirmation — диалог типа «подтверждение», имеет заголовок «Confirm» и рисунок с зеленым вопросительным знаком;
- mtCustom — диалог произвольного типа, имеет заголовок, соответствующий имени выполняемого файла и не содержит изображения.
ПРИМЕЧАНИЕ
Внешний вид изображений, символизирующих диалог того или иного типа, периодически претерпевает некоторые изменения, в зависимости от версии Delphi.
Следующий параметр, имеющий перечисляемый тип TMsgDlgButtons, позволяет указать, какие кнопки должны быть расположены на диалоговом окне. Всего предусмотрено 11 вариантов кнопок, среди них предусмотрены такие, как OK, Cancel, Yes, No и т.д. При этом каждая такая кнопка (кроме Help), будучи нажатой пользователем, закрывает окно, а функция возвращает значение, соответствующее нажатой кнопке. Все варианты кнопок и возвращаемые ими значения, приведены в таблице 10.3.
| Значение | Описание | Возвращаемый результат |
|---|---|---|
| mbYes | Кнопка с надписью «Yes» (да) | mrYes |
| mbNo | Кнопка с надписью «No» (нет) | mrNo |
| mbOK | Кнопка с надписью «OK» | mrOk |
| mbCancel | Кнопка с надписью «Cancel» (отмена) | mrCancel |
| mbAbort | Кнопка с надписью «Abort» (прервать) | mrAbort |
| mbRetry | Кнопка с надписью «Retry» (повторить) | mrRetry |
| mbIgnore | Кнопка с надписью «Ignore» (игнорировать) | meIgnore |
| mbAll | Кнопка с надписью «All» (все) | mrAll |
| mbNoToAll | Кнопка с надписью «No to All» (нет для всех) | mrNoToAll |
| mbYesToAll | Кнопка с надписью «Yes to All» (да для всех) | mrYesToAll |
| mbHelp | Кнопка с надписью «Help» (справка) | — |
Следует оговориться, что все возвращаемые значения, на самом деле, являются целыми числами, что видно по определению функции. Но поскольку запомнить, что, к примеру, возвращаемое значение для OK — это 1, а для Yes — 6, весьма проблематично, то на практике вместо них используются константы, которые как раз и были приведены в таблице 10.3.
Что касается вариантов использования этой функции, то оно сводится к тому, что пользователю выводится какое-либо сообщение, предусматривающее возможность того или иного ответного действия:
MessageDlg('Ошибка чтения с диска. Продолжить?', mtError, [mbRetry, mbAbort], 0);
Поскольку эта функция возвращает то или иное значение, то ее использование часто сопровождается условным оператором:
if MessageDlg('Форматировать диск C:?',mtConfirmation,[mbYes,mbNo],0) = mrYes then FormatDriveCProc();
Другой вариант, для случая с множественными вариантами ответа — использование совместно с оператором-переключателем:
case MessageDlg('Файл изменен. Сохранить перед выходом?', mtWarning, [mbYes, mbNo, mbCancel], 0) of
mrYes: begin SaveFileProc(); Close; end;
mrNo: Close;
mrCancel: exit;
end;
Подобно процедуре ShowMessage, для функции MessageDlg так же предусмотрен вариант с позиционированным выводом окна. Такой вариант этой функции называется MessageDlgPos. Ее отличие от MessageDlg состоит в том, что к списку аргументов добавлено еще 2 параметра, отвечающих за расположение окна. Такой вариант используется, например, при поиске с заменой в текстовых редакторах:
MessageDlgPos('Заменить это вхождение?', mtConfirmation, [mbYes, mbNo], 0, X, Y);
Все рассмотренные нами подпрограммы применяются для вывода сообщений. Что касается ввода, то для этих целей, как уже отмечалось, используют функции InputBox и InputQuery. Обе они выводят окно, позволяющее пользователю ввести какое-либо значение — число или строку. Различие между ними состоит лишь в том, что InputBox возвращает непосредственно результат (в виде строки), а InputQuery — истину или ложь, в зависимости от того, нажмет пользователь OK или Cancel. При этом само значение возвращается в качестве одного из параметров. В итоге мы имеем следующий синтаксис для этих функций:
function InputBox(const ACaption, APrompt, ADefault: string): string;
function InputQuery(const ACaption, APrompt: string; var Value: string): Boolean;
Таким образом, какую из функций лучше использовать в данный момент, зависит от контекста применения. Например, если надо просто получить какое-либо значение от пользователя, то можно использовать функцию InputBox:
UserName := InputBox('Запрос','Введите ваше имя','анонимно');
В данном случае последний параметр функции будет использован в качестве значения по умолчанию (рис. 10.3).

Рис. 10.3. Диалоговое окно функции InputBox
Если же в зависимости от того, введет или нет пользователь новое значение, должна быть выполнена та или иная ветвь алгоритма, то предпочтительнее использовать функцию InputQurey:
if InputQurey('Курс доллара ','Введите новый курс',NewCur) then UpdatePrc();
Помимо приведенных здесь процедур и функций, в VCL имеется ряд иных подпрограмм, использующих диалоговые окна, включая такие, как диалог выбора каталога или файла. Но поскольку их использование сопряжено с некоторыми неудобствами, в частности, им приходится передавать большое число параметров, то на практике для тех же целей чаще используют компоненты. Например, функция PromptForFileName используется для вывода диалога сохранения или открытия файла. Но более типичным (и удобным!) вариантом обращения к таким диалогам является использование таких стандартных компонент VCL, как TOpenDialog и TSaveDialog, с которыми мы познакомимся в следующей части этой книги.
Обработка сообщений и Windows API
Как ни широк охват VCL, иногда все-таки возникает потребность в обращении к функциям Windows напрямую. Например, для того же самого вывода окна с текстовым сообщением можно использовать собственную функцию Windows API — MessageBox:
MessageBox(0, 'Текст сообщения', 'Заголовок', MB_OK);
Необходимость использования функций Windows API может быть вызвана, например, соображениями компактности исполняемого файла: использование диалогов Delphi автоматически подразумевает использование целого рада модулей, необходимых для оконного интерфейса. Если же в самой программе такие модули (например, forms) не задействуются, то их включение в исполняемый код только ради диалога не является хорошей идеей.
В то же время, обращение к функциям Windows API может быть вызвано, например, необходимостью перехвата непредусмотренных в Delphi сообщений.
ПРИМЕЧАНИЕ
Еще одной темой, важной для дальнейшего изучения программирования в Windows вообще и в среде Delphi в частности, является концепция событийного программирования. Дело в том, что хотя ОС Windows, в отличие от Delphi, и не является объектной средой, подход к организации взаимодействия приложений (как с пользователем, так и с системой), основан на одном и том же, а именно — на событиях.
Как мы уже знаем, для событий в VCL используются обработчики событий. Но важно знать, что каждое событие порождает сообщение. Таким образом, отслеживая поступающие сообщения и отсылая собственные, мы можем действовать в обход ограничений VCL.
Для отправки сообщений чаще всего используют функции SendMessage и PostMessage. Обе они выполняют отправку сообщения конкретному окну, разница заключается лишь в том, что SendMessage ожидает ответа от получившего сообщение обработчика, а PostMessage возвращает ответ немедленно. Ценность этих функций состоит в том, что в отличие от средств, предоставляемых VCL, они могут взаимодействовать не только в рамках одного приложения, но и между совершенно разными программами и даже устройствами.
Хотя детальное ознакомления с работой Windows API явно не вписывается в рамки данной книги (не забываем, что Delphi была создана как раз для того, чтобы скрыть сложную и неуклюжую API Windows), отметим все-таки некоторые связанные с ней аспекты. Прежде всего, это касается типов данных. Хотя ранние версии Windows были написаны на Pascal, со временем Microsoft перешла на использование C и C++, поэтому типы данных в представлении Windows несколько отличаются от таковых в Delphi. Прежде всего, это касается строк: при работе с Windows напрямую следует использовать не обычные, а C-строки. В Object Pascal для этого предусмотрен специальный тип данных — PChar, а так же функции для преобразования строк одного вида в другой. Так, для преобразования Pascal-строк в C-строки используют функцию StrPCopy, а для обратного преобразования — функцию StrPas.
var
a: PChar;
s: string;
...
s:='Строка';
new(a); // для С-строк следует предварительно выделять память
StrPCopy(a,s); // содержимое Pascal-строки s скопировано в C-строку a
s:=StrPas(a);
Другие типы данных, часто используемые при работе с API — целые числа, булевы значения и указатели. В таких случаях можно использовать стандартные для Object Pascal типы данных, а к нужному виду они, при необходимости, будут приводиться автоматически.
СОВЕТ
В поставку Delphi включена документация по Windows API. Ссылки на файлы вы найдете в разделе MS SDK Help Files, вложенном в раздел Help программной группы Delphi в меню кнопки пуск. Наибольший интерес с точки зрения изучения функций API представляет собой файл Win32 Programmer’s reference.
Что касается VCL, то в Delphi все же имеется специальный компонент, который может отлавливать все сообщения, адресуемые приложению. Для этого существует компонент AppEvents, который принимает все сообщения, адресованные объекту Application. Среди событий, отслеживаемых компонентом AppEvents, выделим OnMessage — именно это событие происходит, когда приложение получает сообщение от Windows или иной программы. Кроме того, ряд компонент, на самом деле, являются оболочкой для вызова тех или иных функций Windows. Впрочем, о компонентах Delphi будет рассказано в следующей части этой книги.
« Черчение, рисование и печать
|
Работа с VCL в среде Delphi »
Техподдержка / Связаться с нами
Copyright © 1999-2020 SNK. Все права защищены.
При использовании материалов с сайта ссылка на источник обязательна.