Миттєвий Python, Python, Програмування, статті

Переклад: Михайло Олександрович Бєланов

(belanov@starcity.tcnet.ru)


(Magnus Lie Hetland. Instant Python. Оригінал документа:
www.idi.ntnu.no/~mlh/different.html
).


Це мінімальний експрес – курс програмування мовою
Python
(Або
http://www.python.org
, Особливо на сторінці

“Tutorial”

(Або російський переклад цього документа Султанбека Тезадова:
“Comparison”

, Де дається порівняння Python з іншими мовами.

1. Основи

Для початку розглядайте Python як псевдокод. Це майже правда. Змінні начебто не
мають типів – тому їх не потрібно їх оголошувати. Вони виникають, коли ви
привласнюєте їм значення, і зникають, коли ви більше їх не використовуєте. (Типи змінних визначаються автоматично при виконанні програми).
Присвоєння здійснюється оператором

=

, А рівність перевіряється оператором

==

. Ви можете давати значення декільком змінним одночасно:


x, y, z = 1, 2, 3
first, second = second, first

(Прім.перев.: Спочатку обчислюються всі вирази у правій частині рівності,
зліва направо, потім ці значення по черзі присвоюються змінним, перерахованим в лівій частині)


	a = b = 123
	

Блоки операторів позначаються відступами, і

тільки

відступами (ніяких "операторних дужок" на зразок BEGIN – END або фігурних дужок).
Ось деякі звичайні
керуючі структури:


if (x > 10) and (x < 20) : print "ікссс хороший "

if 10 < x < 20 : print "ікссс хороший "

for i in [1, 2, 3, 4, 5] :
print "це – номер циклу:", i

x = 10
while x > 0 :
print "x все ще позитивний"


Перші два приклади еквівалентні.


Мінлива циклу (індекс) в прикладі циклу

for

приймає всі можливі значення з

списку

(List), (який записується як у прикладі). Щоб зробити "звичайний"
цикл (тобто з лічильником кількості виконань), використовуйте вбудовану функцію


range()


.


# Друкує всі значення від 0 до 99 включно:
for value in range (100) :
print value

(Рядок програми, що починається з "#", є коментарем і
ігнорується інтерпретатором).



Добре, тепер ви знаєте достатньо (в теорії), щоб записати будь-який алгоритм
на Python. Давайте додамо деякий елементарний інтерфейс користувача. Щоб
він міг вводити дані (на запрошення програми), використовуйте функцію

input

:


x = input ("Введи сюди число:")
print "Квадрат цього числа складає", x * x


Функція

input

показує заданий запрошення (яке може бути порожнім), дозволяючи
користувачеві ввести будь дозволене в Python значення. У даному прикладі ми
очікуємо, що буде введено число. Але якщо буде введено щось інше (скажімо,
рядок), то трапиться "крах" програми. Щоб уникнути цього, нам знадобиться
якийсь контроль помилок. Я не хочу заглиблюватися в це. Досить сказати, що
якщо ви хочете, щоб те, що ввів користувач, було запасено в програмі
буквально, у вигляді рядка символів, то використовуйте замість

input

функцію

raw_input

.


Зауваження.

Якщо ви хочете, щоб по функції

input

вводилася рядок символів, то користувач повинен в явному вигляді вказувати
лапки навколо неї. У Python для рядків може використовуватися пара як одинарних,
так і подвійних лапок.

Отже, у нас є керуючі структури, введення-виведення, тепер ми хочемо мати
якісь цікаві структури даних (тобто типи все ж є). Найбільш важливими з них є

списки

(List) і

словники

(Dictionary). Списки записуються в квадратних дужках і, природно, можуть
бути вкладеними:



name = [“Cleese”, “John”]
x = [[1, 2, 3], [y, z], [[ ]] ]


Одним з привабливих якостей списків є те, що ви можете звертатися
до їхніх елементів не тільки окремо, але і по групах, використовуючи

індексацію

(Indexing) і

перерізу

(Slicing). Індексація, як і в багатьох інших мовах, проводиться додаванням
до імені списку індексу в квадратних дужках (врахуйте, що перший елемент має
індекс 0).


print name [1], name [0]
Друкує: "John Cleese"
name [0] = “Smith”


Перетини нагадують індекси, однак ви вказуєте початковий і кінцевий індекс,
через ":", отримуючи в результаті подспісок:


x = ["сміття", "сміття", "сміття", "яйця", "и", "сміття"]
print x [3:5]

Друкує список: ["яйця", "і"]


Зверніть увагу, що верхня межа діапазону індексів не включно.
Якщо одна із меж діапазону опущена, то маються на увазі всі елементи в тому
напрямі. Наприклад, вираз

spisok [:3]

означає "кожен елемент списку spisok з першого і до третього, не
включно ". (Ви можете заперечити, що індекс 3 насправді означає четвертий
елемент, оскільки рахунок йде з 0. Дійсно …). З іншого боку, вираз

spisok [3:]

означає "всі елементи списку, починаючи з має індекс 3, включно, і до кінця
списку, включаючи останній ". Дійсно цікавий результат можна отримати,
застосовуючи негативний індекс:

spisok [-3]

це третій елемент з кінця.
Говорячи про індекси, потрібно згадати, що вбудована функція

len

дає довжину списку.

Тепер щодо словників. Говорячи просто, вони схожі на списки, лише елементи
в них не впорядковані. Як ви можете робити індексацію в них? Для цього кожен
елемент має

ключ

(Key), або «ім'я», за яким його можна знайти точно так само, як у звичайному
словнику. Ось кілька прикладів словників:


{“Alice” : 23452532, “Gennady” : 252336, “Clarice” : 2352525}
person = {'ім'я': "Robin", 'фам.' : "Hood", 'заняття': "партизанів"}


Тепер щоб дізнатися, чим займається людина, перерахований в словнику person, ми
використовуємо вираз виду person ['заняття']. Якщо ми хочемо змінити прізвище
людини, ми пишемо:


person ['прізвище'] = "of Locksley"


Просто, чи не так? Як і списки, словники можуть містити в собі інші словники.
Або списки, до речі. І, природно, списки можуть містити в собі словники. Це
дозволяє вам створювати досить складні структури даних.

2. Опції

Наступний крок:

абстракція

. Ми хочемо присвоїти ім'я шматку програмного коду і потім викликати його, задаючи
параметри. Іншими словами, ми хочемо визначати функції (або процедури). Це
легко. Для визначення функції використовуйте ключове слово

def

, Як у прикладі:


def square (x) :
return x*x

print square (2)
Друкує: 4


Для тих з вас, хто розуміє, що це таке: всі параметри функцій в Python
передаються по посиланню (як, наприклад, в Java). Для тих, хто не розуміє: не
піклуйтеся про це нам.
Python має такі привабливі особливості, як іменовані аргументи
функцій і значення для аргументів за замовчуванням. Більш докладно про це див у
Розділі 4.7 "Tutorial"
-А, або в "Tutorial", Розділ 9
(Або
есе Гвідо ван Россум про метакласи на зарубіжному мовою
. Якщо, проте, ви віддасте перевагу не звихнутися, то вас може задовольнити
описана тут маленька хитрість.
Python використовує не лексичні, як зазвичай, а динамічні простору імен.
Це означає, що якщо у вас є функція кшталт:

def orange_juice () :
return x*2


де змінна (в даному випадку x) не пов'язана з аргументом і не отримує
значення всередині функції, то Python використовує те значення, яке вона мала в
момент виклику функції. У даному випадку:


x = 3
orange_juice ()
Повертає: 6

x = 1
orange_juice ()

Повертає: 2


Зазвичай це те поведінку, і яку хочете (хоча наведений приклад кілька
надуманий – ви рідко використовуєте змінні подібним чином). Однак іноді
хочеться мати статичну простір імен, тобто зберігати в тілі функції
деякі значення, задані поза функцією, якими вони були в момент її створення.
Ось як це робиться в Python за допомогою значень для аргументів за замовчунням:


x = 4
def apple_juice (x = x) :
return x*2



Тут аргументу x дається значення за замовчуванням, яке збігається зі значенням
однойменної змінної x, яким воно було під час визначення функції. Таким
чином, якщо викликати функцію без аргументу, то вийде наступне:


x = 3
apple_juice ()
Повертає: 8
x = 1
apple_juice ()
Повертає: 8


Отже, значення x не змінюється. Якби це було все, чого ви хотіли, то ми
могли б з тим же успіхом написати:

def tomato_juice () :
x = 4
return x*2


або навіть:

def carrot_juice () :
return 8


Однак ідея полягає в тому, що значення x береться з програмного оточення
функції і зберігається
таким, яким воно було в момент визначення функції. Як це може бути корисно?
Розглянемо наступний приклад – функція, яка комбінує дві інші функції.
Ми хочемо, щоб функція працювала приблизно так:


from math import sin, cos
sincos = compose (sin, cos)
x = sincos (3)


де compose – функція, яку ми хочемо створити, а x має значення
-0.836021861538, Що дорівнює значенню виразу sin (cos (3)). Тепер, як ми
будемо робити це?
Ясно, що функція compose бере в якості параметрів дві функції, а повертає
ще одну функцію, яка в свою чергу, бере один параметр. Отже,
схема рішення може бути такою:

def compose (fun1, fun2) :
def inner (x) :
# … Задаємо функцію, яка буде
# Повертається значенням для compose
return inner


Ми могли б спробувати помістити в тіло функції inner оператор return fun1
(Fun2 (x)) і зупинитися на цьому. Не можна, однак. Така функція вела б себе
дуже дивно. Уявіть наступний сценарій:

from math import sin, cos
def fun1 (x) :
return x + ” comrade!”
def fun2 (x) :
return “Hello, ”
sincos = compose (sin, cos) # використовуючи неправильну версію


Яке тепер значення x? Правильно, "Hello, comrade!". Чому так? Тому, що
в момент виклику, функція compose бере значення функцій fun1 і fun2 зі свого
програмного оточення, а не ті fun1 і fun2, які були присутні в програмі
в момент створення функції. Все, що нам потрібно зробити, щоб отримати
працююче рішення, це застосувати раніше описаний мною прийом:


def compose (fun1, fun2)
def inner (x, fun1=fun1, fun2=fun2) :
return fun1 (fun2 (x))
return inner


Тепер ми тільки можемо сподіватися, що ніхто не викличе результуючу функцію з
більш ніж одним аргументом, так як це може катастрофічні наслідки для
неї. І, до речі, нам не потрібно вводити ім'я для функції inner – раз вона
містить тільки один вираз, то ми можемо використовувати анонімну функцію,
яка оголошується, використовуючи ключове слово

lambda

замість імені:


def compose (f1, f2) :
return lambda x, f1=f1, f2=f2 : f1 (f2 (x))


Коротко, але все ж зрозуміло. Вам полюбити цей стиль (жарт).

5. А тепер …

Наостанок згадаємо ще кілька речей. Більшість корисних функцій і класів
поміщені в модулі, які фактично представляють собою текстові файли,
містять програмний код на мові Python. Ви можете імпортувати їх в свою
програму і використовувати. Наприклад, щоб використовувати метод

split

зі стандартного модуля

string

, Ви можете зробити наступне:


import string
x = string.split (y)


або …

from string import split
x = split (y)


Більш детально про модулях стандартної бібліотеки, см.
www.python.org/doc/lib
.
Там є дуже багато корисного. Якщо ви хочете, щоб ваша програма могла
працювати і як імпортований модуль, і як незалежна програма, то ви можете
Додати в її кінці рядок виду:


if __name__ == “__main__”: go ()

Це – спосіб перевірити, чи працює програма як виконуваного скрипта
(Тобто не будучи імпортована в інший скрипт) – в цьому випадку буде викликана
функція go. Зрозуміло, замість неї ви можете вкласти після ":" будь-який
програмний код.
І для тих з вас, хто хоче створювати скрипти для UNIX: щоб скрипт працював як
незалежна програма, його першим рядком повинен бути наступний керуючий
коментар:



#!/usr/bin/env python


Нарешті, коротко згадаємо важливе поняття:

винятку

(exception).

Деякі операції, такі як спроба поділу на 0 або читання з
неіснуючого файлу, можуть створювати стан помилки, або виключення. Ви
навіть можете робити свої власні винятки та

порушувати

(Raise) їх у відповідний момент.
Якщо виняток ніяк не обробляється в програмі, то вона завершує свою
роботу з видачею повідомлення про помилку. Ви можете уникнути такого кінця, застосувавши
оператор

try/except

. Наприклад:


def safe_division (a, b): # безпечне розподіл a на b
try :
return a/b
except ZeroDivisionError: # стандартне виняток
# "Ділення на 0"
return None


ZeroDivisionError – це ім'я стандартного виключення ("Поділ на 0"). В даному
прикладі ви могли б перед поділом вкласти перевірку того, що b не дорівнює 0. Але
у багатьох випадках така стратегія непридатна. І. крім того, якби у нас не
було б секції

try

в тілі функції safe_division ("безпечне поділ"), так що по справедливості
нам довелося б назвати її unsafe_division ("небезпечне поділ"), то ми все одно
змогли б обробити це виключення наступним чином:

try:
unsafe_division (a, b)
except ZeroDivisionError:
print "Поділ на 0 у функції unsafe_division"


У випадках, коли у вас зазвичай не повинна виникати деяка проблема, але в
принципі вона все ж може статися, використання обробки виключень позбавить
вас від трудомісткого тестування і.т.п.

Ну от і все. Сподіваюся, ви навчилися чогось.
Тепер ідіть і вступайте в гру
. І
пам'ятайте девіз навчання мови Python:

“Use the source, Luke”

(Користуйся джерелами, Василь Іванович) (переклад: вивчайте всякий текст на
мовою Python, який потрапить вам до рук). Для початку, ось вам приклад. Це
добре відомий алгоритм "швидкої сортування" Хоара.

(Прим. перекл. Для тих,
хто не знає – я докладаю до програми коментар з описом цього алгоритму,
взятим з відомої брошурки Д. Кнута. Я додав цю програму до статті у вигляді Додатку і, крім того, ви можете завантажити qsort.py – Окремий файл з текстом програми. Запуск на виконання – командою python qsort.py)

Одна примітка до цього програмного прикладу. Мінлива done ("виконано")
контролює, завершилося чи розбиття (partition) поточного підсписки
щодо розбиває елемента (pivot), тобто чи всі елементи підсписки
переміщені. Тому коли будь-який з двох внутрішніх процедур хоче завершити всю
послідовність взаємних перестановок елементів, він привласнює done
значення 1 і перериває себе за допомогою

break

. Чому внутрішні цикли повинні використовувати допоміжну змінну done?
Тому, що коли перший внутрішній цикл завершується по

break

, То почне чи ні роботу другий внутрішній цикл залежить від того, завершився
Чи головний цикл, тобто від того, чи було done присвоєно значення 1:


while not done:
while not done:
# Цикли, поки не виконається break

while not done:
# Виконується, тільки якщо в
# Першому циклі done
# Не присвоєно значення 1


Еквівалентний, можливо, більш ясний, але менш красивий варіант:

while not done:
while 1:
# Цикли, поки не виконається break

if not done:
while 1:
# Виконується, тільки якщо
# Done не було присвоєно значення 1


Єдина причина, по якій я використовував змінну done в першому циклі –
це бажання зберегти симетрію між двома циклами. Можна змінити порядок їх
прямування в програмі, а алгоритм, як і раніше буде працювати.
Додаткові приклади див на сторінці
“Tidbit” Джо Строута (Joe Strout)
.

Додаток. Приклад програми QuickSort

Прим. перев.


1) Тут наводиться приклад програми з функцією сортування за алгоритмом "швидкої
сортування "Хоара. Оскільки, не знаючи суть методу, зрозуміти програму важко, то
наводжу його опис, який можна знайти у відомій книжці Д. Кнута та ін,
використовуючи позначення з цього програмного прикладу.


Цей приклад – виключно навчальний, т.к. сортування запрограмована просто
за визначенням методу, без додаткових прийомів підвищення ефективності. І,
крім того, в Python і так є стандартний метод sort, який використовується
так:

Спісок_ітп.sort (ФСравн)

, Де ФСравн – необов'язкова користувацька функція порівняння елементів.
Якщо функцію не вказати, то буде використана стандартна функція

cmp()

, Яка дає "природний порядок" елементів. Наприклад:



a = [2, 5, 1, 3]
a.sort ()
print a
Друкує: [1, 2, 3, 5]

Алгоритм "швидкого сортування" (Quick Sort) Чарльза Хоара (Hoar)

Дано:

список list,
індекси першого і останнього упорядковуваних елементів – start і end.

Змінні:

bottom – менший індекс порівнюваного елемента ("нижнього")

top – більший індекс порівнюваного елемента ("верхнього")

pivot – значення розділяє елемента

partition – допоміжна функція, що ділить список на два підсписки, в одному
з яких всі елементи менше pivot, а в іншому – більше.


Вибирається довільний елемент списку (в даному прикладі – останній, хоча
це
поганий вибір, якщо список вже частково упорядкований). Він називається розділяє
елементом,
т.к. використовується, щоб розділити список на дві частини, так що в одній частині
елементи
будуть менше розділяє, а в іншій більше.
Послідовно перебираються всі елементи відразу з нижнього і верхнього кінця.
Якщо значення нижнього елемента більше pivot, то він пересилається на місце
верхнього (значення якого вже збережено). Якщо верхній елемент більше pivot,
то він пересилається на місце нижнього. Коли індекси верхнього та нижнього елемента
співпадуть, список виявиться розділеним на дві частини – елементи з меншим
індексом, чим він став у розділяє (split), будуть по величині не більший від нього,
а решта – не менше. Отже, невпорядкованість залишиться тільки в
межах цих частин. Рекурсивно застосовуючи цей алгоритм до отриманих частинам
списку, отримуємо в підсумку частини, що складаються з одного елемента, тобто
упорядкований список.

2) На початку програми присутній текстова константа, яка ніде не
використовується. Це не помилка, а необов'язкова, але рекомендована в Python
"Рядок документування" для ідентифікації модуля (класу, функції). Щоб
можна було випробувати програму, виділіть містить її фрагмент цього документа
(Починаючи з рядка

#!/usr/bin/env python

) І збережіть його у вигляді неформатованого текстового файлу
з ім'ям начебто qsort.py (py – тип файлу для програм на Python).

#!/usr/bin/env python

# Written by Magnus Lie Hetland 

"Everybody's favourite sorting algorithm... :)"

def partition(list, start, end):
pivot = list [end] # Нехай останній елем. буде розділяє,
bottom = start-1 # Починаємо ззовні розділяється частині списку
top = end # Аналогічно

    done = 0
while not done: # Ще не всі елем. розділені ...

while not done: # Поки ми не знайдемо
# Неупорядкований елемент ...
bottom = bottom +1 # ... Рухаємо нижній індекс вгору.

if bottom == top: # Якщо він співпаде з верхнім ...
done = 1 # ... то все зроблено.
                break

if list [bottom]> pivot: # Чи не є нижній ел.
# Неупорядкованим?
list [top] = list [bottom] # Тоді переміщаємо його
# На місце верхнього ...
break # ... і починаємо пошук зверху.

while not done: # Ще не знайдемо неупорядкований ел. ...
top = top-1 # ... рухаємо верхній індекс вниз.

if top == bottom: # Якщо він збігся з нижнім ...
done = 1 # ... то все зроблено.
                break

            if list[top] __main__": # Якщо цей скрипт виконується як # незалежна програма: import sys list = sys.argv [1:] # Отримуємо аргументи командного рядка start = 0 end = len (list) -1 quicksort (list, start, end) # Сортуємо весь список аргументів import string print string.join (list) # Роздруковуємо сортований список. sys.exit (0) # Вихід з програми.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*