<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%D0%93%D0%BE%D0%B2%D0%BD%D0%BE</id>
		<title>Linuxformat - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%D0%93%D0%BE%D0%B2%D0%BD%D0%BE"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:Contributions/%D0%93%D0%BE%D0%B2%D0%BD%D0%BE"/>
		<updated>2026-05-13T02:30:09Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF82:Python</id>
		<title>LXF82:Python</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF82:Python"/>
				<updated>2008-06-18T17:04:22Z</updated>
		
		<summary type="html">&lt;p&gt;Говно: «LXF82:Python» переименована в «LXF82: Говно»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{цикл/Python}}&lt;br /&gt;
&lt;br /&gt;
== РАЗРАБОТКА клиент-серверных приложений ==&lt;br /&gt;
''ЧАСТЬ 2 Вознамерились написать открытую альтернативу Skype или собственный клиент BitTorrent? '''Сергей Супрунов''' научит всему необходимому – от основ архитектуры «клиент-сервер» до готовых библиотек для работы с существующими интернет-протоколами.''&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы начали разговор о многозадачности. А&lt;br /&gt;
ведь возможности одновременно выполнять несколько задач&lt;br /&gt;
наиболее востребованы при построении сетевых приложений,&lt;br /&gt;
работающих по схеме «клиент-сервер».&lt;br /&gt;
&lt;br /&gt;
=== Клиент всегда прав ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=UDP-CLIENT.PY&lt;br /&gt;
|Содержание=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
import sys&lt;br /&gt;
from socket import *&lt;br /&gt;
hostname = sys.argv[1]&lt;br /&gt;
HEADER = ‘\x00\x01\x00\x00\x00\x01’&lt;br /&gt;
HEADER += ‘\x00\x00\x00\x00\x00\x00’&lt;br /&gt;
QUESTION = ‘’&lt;br /&gt;
parts = hostname.split(‘.’)&lt;br /&gt;
for p in parts:&lt;br /&gt;
QUESTION += ‘%c%s’ % (chr(len(p)), p)&lt;br /&gt;
QUESTION += ‘\x00\x00\x01\x00\x01’&lt;br /&gt;
QUERY = HEADER + QUESTION&lt;br /&gt;
cs = socket(AF_INET, SOCK_DGRAM)&lt;br /&gt;
cs.sendto(QUERY, (‘127.0.0.1’, 53))&lt;br /&gt;
rsp = cs.recv(1024)&lt;br /&gt;
start = len(QUERY) + 12&lt;br /&gt;
print ‘%s.%s.%s.%s’ % (ord(rsp[start]),&lt;br /&gt;
ord(rsp[start+1]),&lt;br /&gt;
ord(rsp[start+2]),&lt;br /&gt;
ord(rsp[start+3]))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=310px}}&lt;br /&gt;
Наиболее распространенным способом взаимодействия двух приложений через сеть являются уже знакомые нам сокеты. Модуль&lt;br /&gt;
socket, входящий в стандартную поставку Python, помимо рассмотренных в прошлый раз Unix-сокетов поддерживает также сокеты&lt;br /&gt;
домена Internet. Методология использования мало чем отличается от&lt;br /&gt;
Unix-сокетов, за исключением того, что вместо параметра AF_UNIX&lt;br /&gt;
используется AF_INET, а вместо имени файла указываются имя хоста&lt;br /&gt;
и номер порта, которые будут обслуживаться создаваемым сокетом.&lt;br /&gt;
&lt;br /&gt;
В качестве второго параметра в конструкторе сокета можно указать&lt;br /&gt;
его тип: с установлением соединения, соответствующий протоколу TCP,&lt;br /&gt;
или без соединения – протокол UDP. Допустимые значения – SOCK_STREAM и SOCK_DGRAM соответственно. По умолчанию подразумевается SOCK_STREAM.&lt;br /&gt;
&lt;br /&gt;
Как пример, рассмотрим работу приложения, выполняющего роль&lt;br /&gt;
примитивного (и весьма ограниченного функционально) клиента DNS,&lt;br /&gt;
работающего по протоколу UDP (см. листинг udp-client.py).&lt;br /&gt;
&lt;br /&gt;
Некоторую сложность здесь представляет то, что DNS относится к&lt;br /&gt;
так называемым «двоичным» протоколам, в отличие от «текстовых»,&lt;br /&gt;
таких как HTTP или SMTP, где обмен идет обычными текстовыми строками. В случае с DNS оперировать приходится «сырыми» байтами.&lt;br /&gt;
Сведения по формату сообщений можно почерпнуть из RFC 1035, раздел «4. MESSAGES».&lt;br /&gt;
&lt;br /&gt;
В 6-й и 7-й строках рассматриваемого кода формируется заголовок&lt;br /&gt;
(12 байт). Пренебрегая всем богатством возможностей протокола DNS,&lt;br /&gt;
мы ограничиваемся простым запросом (OPCODE=0) одного доменного&lt;br /&gt;
имени (QDCOUNT=1). Конструкции вида «\x00» позволяют задать в&lt;br /&gt;
строке произвольный шестнадцатиричный код.&lt;br /&gt;
&lt;br /&gt;
В строках 8–12 формируется поле запроса. Оно состоит из частей&lt;br /&gt;
доменного имени (в оригинале разделенных точками), перед которыми&lt;br /&gt;
указывается число символов в этой части. Например, имя mail.ru состоит из двух частей (mail – 4 символа, ru – 2 символа) и в запросе должно выглядеть так: \x04mail\x02ru\x00. Завершающий ноль, а также&lt;br /&gt;
два двухбайтовых поля (QTYPE и QCLASS) добавляются к переменной&lt;br /&gt;
QUESTION в строке 12.&lt;br /&gt;
&lt;br /&gt;
Наконец, строки 14 и 15 – создание сокета (обратите внимание на&lt;br /&gt;
второй параметр, SOCK_DGRAM, указывающий тип транспортного протокола UDP) и отправка запроса. Поскольку UDP работает без установки&lt;br /&gt;
соединения, то вместо знакомой нам пары методов «connect – send» мы&lt;br /&gt;
используем один «sendto», в котором указывается сразу и отправляемая информация, и адрес получателя. В данном примере предполагается, что DNS-сервер работает на локальной машине. Вы можете указать&lt;br /&gt;
здесь свой DNS-сервер или передавать его имя в качестве параметра.&lt;br /&gt;
&lt;br /&gt;
И в строках 17–21 из всей полезной информации, возвращаемой&lt;br /&gt;
сервером, мы, игнорируя любые возможные ошибки, выбираем только&lt;br /&gt;
IP-адрес, размещаемый по смещению, которое формируется в переменной start. Результат работы:&lt;br /&gt;
 serg$ ./udp-client.py donpac.ru&lt;br /&gt;
 80.254.111.2&lt;br /&gt;
&lt;br /&gt;
=== Всегда к вашим услугам ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=IAMOK.PY&lt;br /&gt;
|Содержание=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
import os, re&lt;br /&gt;
from socket import *&lt;br /&gt;
class IamOK:&lt;br /&gt;
def __init__(self, host=’localhost’, port=12345):&lt;br /&gt;
self.socket = socket(AF_INET, SOCK_STREAM)&lt;br /&gt;
self.socket.bind((host, port))&lt;br /&gt;
self.socket.listen(5)&lt;br /&gt;
def process(self):&lt;br /&gt;
while 1:&lt;br /&gt;
csocket, caddress = self.socket.accept()&lt;br /&gt;
csocket.send(‘IamOK server v.0.0. Ready to serve.\n’)&lt;br /&gt;
csocket.send(‘You are from %s, port %s...\n’ % caddress)&lt;br /&gt;
while 1:&lt;br /&gt;
request = csocket.recv(64)&lt;br /&gt;
if re.match(‘get\s+uptime’, request, re.IGNORECASE):&lt;br /&gt;
csocket.send(os.popen(‘/usr/bin/uptime’).read())&lt;br /&gt;
elif re.match(‘quit|bye|exit’, request, re.IGNORECASE):&lt;br /&gt;
break&lt;br /&gt;
else:&lt;br /&gt;
csocket.send(‘Unknown command.\n’)&lt;br /&gt;
csocket.close()&lt;br /&gt;
if __name__ == ‘__main__’:&lt;br /&gt;
serv = IamOK()&lt;br /&gt;
serv.process()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=310px}}&lt;br /&gt;
В качестве примера сервера, на этот раз работающего по протоколу TCP,&lt;br /&gt;
рассмотрим такой код (см Листинг iamok.py).&lt;br /&gt;
&lt;br /&gt;
Думаю, вы уже поняли, что он прослушивает указанный порт&lt;br /&gt;
(12345), и при поступлении на него запроса возвращает клиенту вывод утилиты uptime, из которого можно почерпнуть время непрерывной&lt;br /&gt;
работы сервера, число подключенных в данный момент пользователей&lt;br /&gt;
и среднюю загрузку системы.&lt;br /&gt;
&lt;br /&gt;
Здесь все должно быть понятно по прошлому уроку. Два отличия – в конструкторе socket.socket() указывается второй параметр –&lt;br /&gt;
SOCK_STREAM (в данном случае его можно было бы и опустить, т.к.&lt;br /&gt;
для Internet-домена и так по умолчанию используется протокол TCP).&lt;br /&gt;
И метод bind() осуществляет привязку сокета не к файлу, а к имени&lt;br /&gt;
хоста и номеру порта, на котором будут ожидаться входящие соединения. Кстати, выбирая номер порта, не забывайте, что порты до 1024-го&lt;br /&gt;
относятся к привилегированным и могут быть задействованы только&lt;br /&gt;
пользователем root.&lt;br /&gt;
&lt;br /&gt;
Наш сервер понимает две команды: «get uptime», по которой возвращается информация о времени работы сервера, и «quit» (с двумя&lt;br /&gt;
синонимами – «bye» и «exit»), по которой сеанс завершается.&lt;br /&gt;
&lt;br /&gt;
Проверить работу сервера можно с помощью обычной&lt;br /&gt;
telnet-сессии:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
admin@dom:~/lxf/propy/l2$ telnet localhost 12345&lt;br /&gt;
Trying 127.0.0.1...&lt;br /&gt;
Connected to localhost.localdomain.&lt;br /&gt;
Escape character is ‘^]’.&lt;br /&gt;
IamOK server v.0.0. Ready to serve.&lt;br /&gt;
You are from 127.0.0.1, port 2650...&lt;br /&gt;
helo&lt;br /&gt;
Unknown command.&lt;br /&gt;
get uptime&lt;br /&gt;
23:09:26 up 58 min, 3 users, load average: 0.04, 0.15, 0.63&lt;br /&gt;
quit&lt;br /&gt;
Connection closed by foreign host.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Какая от этого может быть польза – решайте сами.&lt;br /&gt;
&lt;br /&gt;
=== «Гуртом и батьку бить веселей» ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=THREAD-TEST.PY&lt;br /&gt;
|Содержание=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf8 -*-&lt;br /&gt;
import threading as t&lt;br /&gt;
import time, re&lt;br /&gt;
diskbusy = t.Lock()&lt;br /&gt;
def parseit(lognum):&lt;br /&gt;
global errors, total&lt;br /&gt;
diskbusy.acquire()&lt;br /&gt;
log = open(‘logs/syslog.%d’ % lognum)&lt;br /&gt;
lines = log.readlines()&lt;br /&gt;
diskbusy.release()&lt;br /&gt;
for line in lines:&lt;br /&gt;
if re.search(‘failed|error’, line):&lt;br /&gt;
errors += 1&lt;br /&gt;
total += 1&lt;br /&gt;
class ParseLog(t.Thread):&lt;br /&gt;
def __init__(self, num):&lt;br /&gt;
self.lognum = num&lt;br /&gt;
t.Thread.__init__(self)&lt;br /&gt;
&lt;br /&gt;
def run(self):&lt;br /&gt;
parseit(self.lognum)&lt;br /&gt;
#------------------ 1&lt;br /&gt;
def test1():&lt;br /&gt;
global errors, total&lt;br /&gt;
errors = total = 0&lt;br /&gt;
for i in range(10):&lt;br /&gt;
parseit(i)&lt;br /&gt;
print errors, total,&lt;br /&gt;
#------------------ 2&lt;br /&gt;
def test2():&lt;br /&gt;
global errors, total&lt;br /&gt;
errors = total = 0&lt;br /&gt;
running = []&lt;br /&gt;
for i in range(10):&lt;br /&gt;
tr = ParseLog(i)&lt;br /&gt;
tr.start()&lt;br /&gt;
running.append(tr)&lt;br /&gt;
for tr in running:&lt;br /&gt;
tr.join()&lt;br /&gt;
&lt;br /&gt;
print errors, total,&lt;br /&gt;
start = time.time()&lt;br /&gt;
test1()&lt;br /&gt;
print ‘Послед.: %f’ % (time.time() - start)&lt;br /&gt;
start = time.time()&lt;br /&gt;
test2()&lt;br /&gt;
print ‘Потоки: %f’ % (time.time() - start)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=310px}}&lt;br /&gt;
Потоки, наряду с рассмотренными ранее процессами, являются эффективным способом параллельного выполнения различных задач. В&lt;br /&gt;
ряде случаев этим можно воспользоваться не только для одновременного обслуживания нескольких подключений в клиент-серверных&lt;br /&gt;
приложениях, но и для повышения производительности «автономных»&lt;br /&gt;
программ.&lt;br /&gt;
&lt;br /&gt;
Например, пусть у нас есть каталог с десятком достаточно больших&lt;br /&gt;
журнальных файлов. Их требуется обработать, подсчитав число строк,&lt;br /&gt;
в которых встречаются сообщения об ошибках. Данная задача создает нагрузку как на дисковую подсистему, так и на процессор. Но при&lt;br /&gt;
последовательной обработке ресурсы будут расходоваться неэффективно – пока выполняется чтение очередного файла, процессор простаивает. Напротив, во время обработки считанных данных бездействует&lt;br /&gt;
диск. Таким образом, здесь есть потенциал для оптимизации за счет&lt;br /&gt;
обработки каждого файла в отдельном потоке.&lt;br /&gt;
&lt;br /&gt;
В стандартной поставке Python для работы с потоками есть два&lt;br /&gt;
модуля – thread и threading. Первый позволяет управлять потоками на&lt;br /&gt;
достаточно низком уровне, второй – использует средства первого для&lt;br /&gt;
предоставления более удобного объектно-ориентированного интерфейса. Класс threading.Thread предоставляет «шаблон» потока. Для его&lt;br /&gt;
использования в своей программе вам нужно переопределить метод&lt;br /&gt;
run(), описав в нем действия, которые должны выполняться этим потоком. Ниже приведен пример, из которого все должно стать понятно.&lt;br /&gt;
&lt;br /&gt;
Нужно заметить, что при распараллеливании «в лоб», когда просто&lt;br /&gt;
запускается сразу несколько потоков, по одному на каждый обрабатываемый файл, нас поджидает один неприятный сюрприз (можете&lt;br /&gt;
проверить это на досуге) – при старте сценария все созданные потоки&lt;br /&gt;
одновременно попытаются выполнить чтение нужных им для дальнейшей работы данных. Это приведет к жесткой конкуренции за право переместить головки винчестера в нужное место и вызовет, вопреки ожидаемому, катастрофическое падение производительности. Если размеры&lt;br /&gt;
файлов сопоставимы с объемом оперативной памяти, система, ко всему&lt;br /&gt;
прочему, может «впасть в своппинг», когда считанные одним потоком&lt;br /&gt;
данные будут тут же записываться на диск, чтобы освободить место для&lt;br /&gt;
данных другого потока.&lt;br /&gt;
&lt;br /&gt;
Вот если бы нам удалось организовать работу потоков таким образом, чтобы, пока один из них выполняет чтение файла, другие не обращались к диску... Для решения этой задачи в языке Python доступно&lt;br /&gt;
несколько средств синхронизации работы потоков.&lt;br /&gt;
Простейшее из них – использование обычных переменных-флагов.&lt;br /&gt;
Как вы помните, потоки разделяют оперативную память, принадлежащую процессу, в рамках которого они исполняются, так что изменения&lt;br /&gt;
переменных будут «видны» всем процессам. Идея здесь проста:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
if DISKBUSY:&lt;br /&gt;
# ожидание&lt;br /&gt;
else:&lt;br /&gt;
DISKBUSY = 1&lt;br /&gt;
# чтение файла&lt;br /&gt;
DISKBUSY = 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
То есть первый поток выставит истинное значение глобальной переменной DISKBUSY и приступит к чтению файла. «Опоздавшие» потоки&lt;br /&gt;
будут ждать, пока переменная вновь не примет значение «ложь».&lt;br /&gt;
&lt;br /&gt;
В такой реализации программисту предстоит решить не такую уж&lt;br /&gt;
простую, как может показаться на первый взгляд, задачу – грамотно&lt;br /&gt;
обеспечить ожидание. Бесконечный цикл проверки значения переменной слишком сильно нагружает процессор (не даром такие циклы&lt;br /&gt;
называют напряженными). Напрашивающееся time.sleep(1) очень&lt;br /&gt;
не эффективно – если ресурс освободится до того, как истечет время «спячки», то он будет простаивать. [Кроме того, подобный метод&lt;br /&gt;
синхронизации сам по себе не атомарен – подробности ищите в статье&lt;br /&gt;
«[[LXF82:Unix API|Очереди сообщений и семафоры]]»]&lt;br /&gt;
&lt;br /&gt;
Однако в модуле threading есть готовая реализация описанной&lt;br /&gt;
выше идеи – класс Lock, который предоставляет программисту так&lt;br /&gt;
называемые блокировки, иногда именуемые «мьютексами» (mutex).&lt;br /&gt;
Идя проста – создается объект данного класса (threading.Lock()),&lt;br /&gt;
который имеет два метода: acquire() позволяет захватить объект,&lt;br /&gt;
release() – освободить его. Метод aquire() является блокирующим:&lt;br /&gt;
очередной поток, вызвавший его, будет ждать до тех пор, пока мьютекс&lt;br /&gt;
не освободится.&lt;br /&gt;
&lt;br /&gt;
Дальнейшим развитием идеи блокировок являются семафоры.&lt;br /&gt;
Фактически, семафор – это тот же мьютекс, но позволяющий захватить себя несколько раз. Если вы создадите семафор командой&lt;br /&gt;
semaphore = threading.Semaphore(3), то его смогут захватить (тем&lt;br /&gt;
же методом semaphore.acquire()) одновременно три потока (каждый раз отнимая по единице из указанного при инициализации числа).&lt;br /&gt;
Четвертый поток сможет захватить семафор только после того, как он&lt;br /&gt;
будет высвобожден (semaphore.release()) одним из тех, которые&lt;br /&gt;
удерживают его в настоящее время.&lt;br /&gt;
&lt;br /&gt;
Впрочем, для нашей задачи лучше всего подходят мьютексы – диск&lt;br /&gt;
объявим неразделяемым ресурсом, и посмотрим, какой выигрыш по&lt;br /&gt;
времени это нам даст (см. листинг thread-test.py).&lt;br /&gt;
&lt;br /&gt;
Здесь мы проводим два теста – последовательная обработка (1) и&lt;br /&gt;
использование потоков с эксклюзивным доступом к диску (2). В строках&lt;br /&gt;
16–22 мы создаем подкласс класса Thread, в котором переопределяем&lt;br /&gt;
метод run(). Запуск потока выполняется в строке 37. Обратите внимание&lt;br /&gt;
на список running (строки 34, 38, 39–40). С его помощью мы отслеживаем активность потоков – метод join() заставляет ждать, пока поток не&lt;br /&gt;
завершит свою работу. Дальнейшая работа основного сценария продолжится только после того, как отработают все порожденные потоки.&lt;br /&gt;
&lt;br /&gt;
В строке 5 мы создаем мьютекс, с помощью которого в строках 8 и 11&lt;br /&gt;
будет регулироваться доступ потоков к диску. В глобальной переменной&lt;br /&gt;
errors ведется подсчет числа строк, в которых есть подстрока «failed» или&lt;br /&gt;
«error», в total – общее число обработанных строк. Результат работы:&lt;br /&gt;
 21931 2302755 Послед.: 33.271387&lt;br /&gt;
 21931 2302755 Потоки: 22.867245&lt;br /&gt;
Как видите, мы получили выигрыш по времени более чем на 30%.&lt;br /&gt;
Но нужно заметить, что распараллеливание подобных скриптов даст&lt;br /&gt;
заметный эффект только в том случае, если нагрузка на дисковую систему сопоставима с нагрузкой на процессор. Если какой-то из ресурсов&lt;br /&gt;
будет востребован намного больше второго, то потокам все равно придется ждать его высвобождения, а с учетом дополнительных затрат на&lt;br /&gt;
обслуживание самих потоков, суммарный результат может оказаться&lt;br /&gt;
даже хуже, чем при последовательной обработке.&lt;br /&gt;
&lt;br /&gt;
=== Все включено ===&lt;br /&gt;
В поставку Python входит несколько готовых модулей, позволяющих&lt;br /&gt;
легко и быстро разработать сетевую программу, например, HTTP-сервер или FTP-клиент. Более детально вы сможете познакомиться с ними&lt;br /&gt;
в документации или в хорошо прокомментированных исходных кодах&lt;br /&gt;
самих модулей. Здесь же рассмотрим их возможности обзорно.&lt;br /&gt;
&lt;br /&gt;
=== HTTP ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=HTTP-SERVER.PY&lt;br /&gt;
|Содержание=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf8 -*-&lt;br /&gt;
import SimpleHTTPServer as http&lt;br /&gt;
handler = http.SimpleHTTPRequestHandler&lt;br /&gt;
server = http.BaseHTTPServer.HTTPServer((‘localhost’, 8080), handler)&lt;br /&gt;
server.serve_forever()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=310px}}&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=HTTP-CLIENT.PY&lt;br /&gt;
|Содержание=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf8 -*-&lt;br /&gt;
import httplib&lt;br /&gt;
host = httplib.HTTP(‘localhost:8080’)&lt;br /&gt;
host.putrequest(‘GET’, ‘/testpage.html’)&lt;br /&gt;
host.putheader(‘accept’, ‘text/html’)&lt;br /&gt;
host.endheaders()&lt;br /&gt;
code, msg, headers = host.getreply()&lt;br /&gt;
print code, msg&lt;br /&gt;
if code == 200:&lt;br /&gt;
print host.getfile().read()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=310px}}&lt;br /&gt;
Для работы с HTTP Python предоставляет четыре основных модуля:&lt;br /&gt;
BaseHTTPServer, SimpleHTTPServer, CGIHTTPServer и httplib.&lt;br /&gt;
Первые три реализуют простейшие серверы, причем второй и третий&lt;br /&gt;
модули используют возможности первого, предоставляя программисту&lt;br /&gt;
более высокоуровневый интерфейс к его методам. Модуль httplib служит для разработки HTTP-клиентов.&lt;br /&gt;
&lt;br /&gt;
Например, простейший HTTP-сервер может выглядеть таким образом (см. листинг http-server.py).&lt;br /&gt;
&lt;br /&gt;
Как видите – всего четыре «рабочих» строчки, и то строка под номером 4 служит лишь для присвоения столь длинного имени метода-обработчика более короткой и удобной переменной. Вести себя этот сервер&lt;br /&gt;
будет как «самый настоящий»: он будет возвращаться запрошенные&lt;br /&gt;
html-страницы или файлы из текущего и вложенных в него каталогов,&lt;br /&gt;
при наличии файлов index.html или index.htm в каталоге, из которого сервер запущен, клиенту по умолчанию (когда указано только имя&lt;br /&gt;
каталога) будут отдаваться они. Если индексные файлы отсутствуют,&lt;br /&gt;
автоматически будет строиться страница-содержание каталога (аналогично работает Apache с включенным модулем mod_autoindex). В&lt;br /&gt;
ответ на запрос несуществующего ресурса будут возвращаться сообщения об ошибке, и т.д.&lt;br /&gt;
&lt;br /&gt;
Клиентское приложение будет не намного сложнее (см Листинг&lt;br /&gt;
http-client.py).&lt;br /&gt;
&lt;br /&gt;
В строках 4–7 формируется нужный HTTP-заголовок, затем получаем и распечатываем ответ сервера:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;html4strict&amp;quot;&amp;gt;&lt;br /&gt;
admin@dom:~/lxf/propy/l2$ ./http-client.py&lt;br /&gt;
200 OK&lt;br /&gt;
&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&lt;br /&gt;
&amp;lt;TITLE&amp;gt;Test page&amp;lt;/TITLE&amp;gt;&lt;br /&gt;
&amp;lt;/HEAD&amp;gt;&amp;lt;BASE&amp;gt;&lt;br /&gt;
&amp;lt;H2&amp;gt;It is a test page&amp;lt;/H2&amp;gt;&lt;br /&gt;
&amp;lt;/BASE&amp;gt;&amp;lt;/HTML&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Конечно, чтобы представить эту страницу в графическом отформатированном виде, придется приложить еще немало усилий. Но это, как&lt;br /&gt;
говорится, уже дело техники.&lt;br /&gt;
&lt;br /&gt;
=== Электронная почта ===&lt;br /&gt;
Модули smtplib, poplib, imaplib предоставляют клиентские интерфейсы к соответствующим протоколам. Их использование не намного&lt;br /&gt;
сложнее рассмотренного выше httplib, и, думаю, вы без труда в них&lt;br /&gt;
разберетесь. Для более тонкой обработки содержимого почтовых сообщений (выделения заголовков, вложений и т.д.) вам помогут модули&lt;br /&gt;
rfc822, mimetools, multifile, base64, mailbox и другие. Все они&lt;br /&gt;
очень хорошо прокомментированы и снабжены достаточно подробной&lt;br /&gt;
документацией. Простейший способ получить к ней доступ – функция&lt;br /&gt;
help(). Например:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; import mailbox&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; help(mailbox)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Этот код выведет встроенную справку по работе с модулем mailbox&lt;br /&gt;
прямо в окне интерактивного терминала.&lt;br /&gt;
&lt;br /&gt;
=== FTP ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=FTP-CLIENT.PY&lt;br /&gt;
|Содержание=&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: uft-8 -*-&lt;br /&gt;
import ftplib&lt;br /&gt;
ftp = ftplib.FTP(‘ftp.freebsd.org’)&lt;br /&gt;
ftp.login(‘ftp’, ‘my@mail.ru’)&lt;br /&gt;
ftp.cwd(‘pub/FreeBSD’)&lt;br /&gt;
retfile = ‘README.TXT’&lt;br /&gt;
ftp.retrbinary(‘RETR %s’ % retfile,&lt;br /&gt;
open(retfile, ‘w+’).write, 1024)&lt;br /&gt;
ftp.quit()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=310px}}&lt;br /&gt;
Для работы с протоколом FTP к вашим услугам модуль ftplib. Работа с&lt;br /&gt;
ним ведется на достаточно низком уровне, и порой напоминает обычный&lt;br /&gt;
сеанс FTP, выполняемый вручную (см. листинг ftp-client.py).&lt;br /&gt;
&lt;br /&gt;
В итоге выполнения этого скрипта в текущем каталоге должен появиться файл README.TXT, скачанный с ftp-сервера ftp://ftp.freebsd.org.&lt;br /&gt;
&lt;br /&gt;
=== Заключение ===&lt;br /&gt;
Итак, на этом мы завершим знакомство с основными сетевыми возможностями языка Python. Хочу заметить, что они выходят далеко за рамки&lt;br /&gt;
простейших сценариев, пригодных для тестирования «больших» серверов или встраивания некоторых сетевых возможностей в ваши приложения. Приведу лишь несколько примеров. Так, в 90-х годах большой популярностью пользовался web-браузер Grail, разработанный на Python и&lt;br /&gt;
предоставляющий весьма широкие для того времени возможности по&lt;br /&gt;
обработке интернет-страниц – полная поддержка стандарта HTML 2.0&lt;br /&gt;
и, в значительной мере, HTML 3.2, поддержка различных форматов&lt;br /&gt;
изображений и звука, способность работать с языком разметки SGML,&lt;br /&gt;
поддержка FTP, и т.д.&lt;br /&gt;
&lt;br /&gt;
Менеджер почтовых рассылок Mailman обеспечивает широкие возможности по управлению списками рассылок, включая web-интерфейс. Интернет-сервер Medusa обладает достаточно хорошими&lt;br /&gt;
характеристиками, позволяя использовать его как для тестовых&lt;br /&gt;
целей, так и для промышленной эксплуатации. Популярный&lt;br /&gt;
сервер web-приложений Zope также полностью разработан&lt;br /&gt;
на языке Python.&lt;br /&gt;
&lt;br /&gt;
Таким образом, этот язык способен решать весьма серьезные сетевые задачи, причем эти решения, как правило,&lt;br /&gt;
обладают весьма высокой переносимостью между различными системами и платформами.&lt;br /&gt;
&lt;br /&gt;
В следующий раз мы рассмотрим способы взаимодействия с&lt;br /&gt;
базами данных, а также убедимся, что Python очень хорош и для разработки динамических web-сайтов.&lt;/div&gt;</summary>
		<author><name>Говно</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF78:Python</id>
		<title>LXF78:Python</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF78:Python"/>
				<updated>2008-06-18T17:03:41Z</updated>
		
		<summary type="html">&lt;p&gt;Говно: «LXF78:Python» переименована в «Говно:Python»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{цикл/Python}}&lt;br /&gt;
''Часть 4. Мы вплотную подошли к наиболее интересной теме – реализации объектно-ориентированного подхода в языке Python. Репортаж с места событий ведет '''Сергей Супрунов.''' ''&lt;br /&gt;
&lt;br /&gt;
===Немного терминологии===&lt;br /&gt;
ООП (объектно-ориентированное программирование), наряду с анализом и дизайном – это важнейшая часть очень популярного объектного подхода к разработке программного обеспечения. В данном случае в дизайне программы выделяются так называемые объекты, которые обладают атрибутами (свойствами) и методами (способами изменения свойств).&lt;br /&gt;
&lt;br /&gt;
Новые объекты создаются на базе классов, которые являются своего рода шаблонами, описывающими общие характеристики объектов (также называемых экземплярами класса).&lt;br /&gt;
&lt;br /&gt;
Для ООП характерны следующие принципы:&amp;lt;br /&amp;gt;&lt;br /&gt;
* инкапсуляция: экземпляр класса рассматривается как «чёрный ящик», когда его внутреннее устройство скрыто, а всё взаимодействие с объектом выполняется через предусмотренный для этого интерфейс, т.е. набор методов. Нужно заметить, что в Python программист, в принципе, имеет возможность непосредственно воздействовать на свойства объекта, минуя интерфейс – здесь инкапсуляция реализована не на уровне ограничений языка, а на уровне соглашений. &lt;br /&gt;
* наследование: вы можете создавать новые классы на базе существующих, при этом они будут получать все атрибуты и методы, описанные для родительских классов. Наследование – это наиболее естественный путь разработки классов, подобных родительским, но с дополнительным набором свойств.&lt;br /&gt;
&lt;br /&gt;
Есть и другие принципы (полиморфизм, аггрегация и т.д.), с которыми вы сможете глубже познакомиться в специальной литературе.&lt;br /&gt;
&lt;br /&gt;
===Реализация ООП в Python===&lt;br /&gt;
&lt;br /&gt;
В отличие от Perl, в Python объектный подход заложен в основу этого языка. Здесь почти всё является объектами, даже строки и числа. Не верите? Смотрите сами:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print 1.0.__add__(5)&lt;br /&gt;
 6.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
То есть мы применили к числу 1.0 (объекту) метод __add__(), который является «внутренней» реализацией операции сложения. Нужно заметить, что здесь из-за ограничений синтаксиса мы вынуждены использовать число с плавающей запятой, поскольку первая точка воспринимается интерпретатором именно как разделитель целой и дробной частей, а вот вторая уже отделяет объект от имени метода. Уже известная нам функция dir(3) вернёт ещё 52 метода, которые вы можете применять к числу.&lt;br /&gt;
&lt;br /&gt;
Для определения класса используется специальный оператор class:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 #!/usr/bin/python&lt;br /&gt;
 # file: сtest.py&lt;br /&gt;
 class &lt;br /&gt;
   comment = 'User'&lt;br /&gt;
   def __init__(self, username):&lt;br /&gt;
     self.username = username&lt;br /&gt;
     self.password = ''&lt;br /&gt;
   def setpass(self, value=''):&lt;br /&gt;
     self.password = value&lt;br /&gt;
   def checkpass(self, typed):&lt;br /&gt;
     if typed == self.password:&lt;br /&gt;
       return 1&lt;br /&gt;
     else:&lt;br /&gt;
       return 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы определили класс, экземпляры которого будут хранить  информацию о пользователях (имя и пароль). Специальный метод '''__init__()''', играющий роль конструктора, автоматически исполняется при создании нового объекта. В нём мы присваиваем атрибуту username значение, переданное конструктору как параметр, и создаём атрибут password с пустым значением.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на обязательность использования параметра '''self''', который должен быть первым в описании любого метода. При работе с конкретным объектом здесь будет указываться его идентификатор, чтобы интерпретатор мог определить, с каким же объектом он имеет дело.&lt;br /&gt;
&lt;br /&gt;
Описанные далее методы setpass() и checkpass() служат для того, чтобы установить значение атрибута password и сравнить с ним значение, введённое пользователем. На практике работа с нашим классом может выглядеть таким образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 u1 = User('Vasya')&lt;br /&gt;
 u1.setpass('qwerty')&lt;br /&gt;
 userpass = raw_input('Enter your password:')&lt;br /&gt;
 if u1.checkpass(userpass):&lt;br /&gt;
  print 'Password is OK'&lt;br /&gt;
 else:&lt;br /&gt;
  print 'Password is wrong'&lt;br /&gt;
 u1.password = 'sasdf'&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В первой строке мы создали объект (экземпляр класса User). Затем мы задали ему пароль и чуть позже сравнили его с тем, который пользователь ввёл по запросу сценария.&lt;br /&gt;
&lt;br /&gt;
Последняя строка демонстрирует, что пароль можно изменить и непосредственно. Это является нарушением принципа инкапсуляции. Язык Python предусматривает два соглашения для решения этой проблемы: во-первых, если имя атрибута или метода начинается с символа подчёркивания, это является признаком того, что они предназначены для «внутреннего потребления» и не должны использоваться непосредственно. Однако сам Python никак не ограничивает это. Если вы желаете получить более жёсткий контроль, используйте имена, начинающиеся двумя символами подчёркивания. Такое имя уже не будет доступно через пространство имён объекта (хотя обходной путь всё же есть).&lt;br /&gt;
&lt;br /&gt;
Особое место занимают специальные методы (такие как показанный выше метод '''__init__()'''). Эти методы реализуют ряд «сервисных» функций (например, конструктор '''__init__()''', '''деструктор __del__()''', отвечающий за корректное удаление объекта, и т.п.), а также позволяют переопределить поведение, заложенное в интерпретаторе. Например, метод '''__add__()''' исполняется при обработке оператора сложения «+».&lt;br /&gt;
Определим его для некоторого класса:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 #!/usr/bin/python&lt;br /&gt;
 # file: stest.py&lt;br /&gt;
 class Test:&lt;br /&gt;
  def __init__(self, value):&lt;br /&gt;
    self.value = value&lt;br /&gt;
  def __add__(self, other):&lt;br /&gt;
   return self.value – other&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И теперь, вместо ожидаемого сложения, мы увидим вычитание:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; from stest import Test&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; a = Test(5)&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print a + 3&lt;br /&gt;
 2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Естественно, этим не стоит злоупотреблять, но вы должны знать, что очень многие «стереотипы» становятся весьма условными, если речь заходит о Python.&lt;br /&gt;
&lt;br /&gt;
Нужно заметить, что вы можете задавать атрибуты объекта динамически, что называется, «на лету». Продолжим предыдущий пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; a.description = 'Описание'&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print a.description &lt;br /&gt;
 Описание&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Хотя атрибут '''description''' отсутствует в классе Test, мы можем работать с ним, как с обычным. Таким образом можно задать и атрибуты, имена которых начинаются с двух подчёркиваний. Это создаёт видимость того, что никаких ограничений на эти имена нет, но на самом деле получится совершенно иной атрибут, нежели определённый в описании класса. Так что не увлекайтесь подчёркиваниями.&lt;br /&gt;
&lt;br /&gt;
===Наследование===&lt;br /&gt;
&lt;br /&gt;
Несколько слов нужно сказать о наследовании. Рассмотрим пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 #!/usr/bin/python&lt;br /&gt;
 # file: ntest.py&lt;br /&gt;
 from ctest import User&lt;br /&gt;
 class ShellUser(User):&lt;br /&gt;
   def __init__(self, username):&lt;br /&gt;
    User.__init__(self, username)&lt;br /&gt;
    self.shell = '/bin/sh'&lt;br /&gt;
   def setshell(self, newshell):&lt;br /&gt;
    self.shell = newshell&lt;br /&gt;
 u2 = ShellUser('Petya')&lt;br /&gt;
 u2.setpass('12345')&lt;br /&gt;
 print u2.password, u2.shell&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видите, дочерний класс ShellUser получает все свойства родительского (имена родительских классов перечисляются в скобках в определении class). Теперь мы можем расширить этот класс новыми атрибутами и методами, и в дальнейшем использовать их наряду с определёнными в родительских классах.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что при создании экземпляра нового класса исполняется только его метод '''__init__()''', инициализацию родительского класса нужно вызывать явно.&lt;br /&gt;
&lt;br /&gt;
===Классы в стандартных модулях===&lt;br /&gt;
Классы очень широко используются в стандартных модулях Python. В качестве примера рассмотрим один достаточно полезный модуль –'''StringIO'''. С его помощью вы можете применять к строкам методы работы с файлами ('''read()''', '''write()''' и т.д.). Это может быть необходимо в тех случаях, когда другой метод или функция может обрабатывать только файлы. Например, класс Message модуля '''rfc822''', с помощью которого, в частности, можно разбирать сообщения электронной почты, умеет работать только с файлом, содержащим текст сообщения.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 #!/usr/bin/python&lt;br /&gt;
 import rfc822, StringIO&lt;br /&gt;
 mailstr = &amp;quot;&amp;quot;&amp;quot;\&lt;br /&gt;
 From: user@domain.ru&lt;br /&gt;
 To: me@mysite.ru&lt;br /&gt;
 Subject: Test Message&lt;br /&gt;
 Hello!&lt;br /&gt;
 It is a test message.&lt;br /&gt;
 &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 fileobj = StringIO.StringIO(mailstr)&lt;br /&gt;
 message = rfc822.Message(fileobj)&lt;br /&gt;
 print &amp;quot;%s wrote:\n&amp;quot; % message.getheader('From')&lt;br /&gt;
 bodyfrom = message.startofbody&lt;br /&gt;
 fileobj.seek(bodyfrom)&lt;br /&gt;
 body = fileobj.read()&lt;br /&gt;
 print body&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итак, что здесь происходит? Переменная mailstr содержит текст в формате почтового сообщения. Поскольку модуль '''rfc822''' умеет работать только с файловыми объектами, мы создаём экземпляр класса '''StringIO''' под именем '''fileobj'''. На его основе уже создаётся объект message класса Message, описанного в модуле rfc822.&lt;br /&gt;
&lt;br /&gt;
С помощью метода getheader() мы распечатываем значение поля «From», а узнав из атрибута startofbody объекта message, где начинается тело сообщения (отделённое от заголовка пустой строкой), мы видим, что нашему объекту fileobj не чужды никакие методы настоящих файлов – можно позиционировать указатель (метод '''seek()'''), считывать содержимое от текущей позиции до конца файла ('''read()'''), и т.д.&lt;br /&gt;
&lt;br /&gt;
===Документируй это!===&lt;br /&gt;
&lt;br /&gt;
Хотя в языке Python инкапсуляция, т.е. сокрытие внутреннего устройства класса, не реализована в чистом виде (вы можете обращаться напрямую к любому атрибуту, за небольшим исключением), но всё же хорошим тоном считается работать с объектами классов только через предоставляемый ими интерфейс. И в этих условиях особое значение приобретает документация. В Python реализован очень удобный способ, скажем так, «онлайновой» документации – первая текстовая строка класса (или функции) воспринимается как его описание, которое может быть в любое время получено с помощью атрибута '''__doc__''':&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; class Cla:&lt;br /&gt;
 ... &amp;quot;Документация класса&amp;quot;&lt;br /&gt;
 ... pass&lt;br /&gt;
 ...&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; print Cla.__doc__&lt;br /&gt;
 Документация класса&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для многострочных описаний удобно использовать утроенные кавычки.&lt;br /&gt;
&lt;br /&gt;
На этом мы завершим наше знакомство с классами Python. Естественно, на таких небольших примерах их мощь и удобство остались за кадром, хотя при работе со стандартными модулями в любом случае необходимо понимать, как всё это работает. Настоящий же эффект от использования объектно-ориентированного подхода вы ощутите при работе над большими проектами.&lt;/div&gt;</summary>
		<author><name>Говно</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF70:Perl._%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D0%B8_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D1%8B</id>
		<title>LXF70:Perl. Переменные и операторы</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF70:Perl._%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D0%B8_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D1%8B"/>
				<updated>2008-06-18T17:03:07Z</updated>
		
		<summary type="html">&lt;p&gt;Говно: «LXF70:Perl. Переменные и операторы» переименована в «Говно и операторы»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Perl}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Perl. Переменные и операторы =&lt;br /&gt;
Часть 1. ''В «эпизоде 1» нашей серии '''Марко Фиоретти''' ('''Marco Fioretti''') объясняет основные компоненты языка Perl.''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Врезка |&lt;br /&gt;
Заголовок=Подсказка |&lt;br /&gt;
Содержание='''Руководства по Perl'''&amp;lt;br /&amp;gt;&lt;br /&gt;
Perl — зрелый язык, и его пользователи имеют доступ к большому количеству различной документации. Книга Тома Кристиансена, Джона Орванта, Ларри Уолла «Программирование на Perl» (Programming Perl by Larry Wall, Jon Orwant and tom Christiansen, O'Reilly) является прекрасным началом, если вам нужна более подробная информация — к вашим услугам http://perl.oreilly.com. Для доступа к онлайновой документации, полной коллекции модулей, руководств и примеров посетите Comprehensive Perl Archive Network (http://www.cpan.org). Отдельные вопросы можно задавать в новостной группе [http://groups.google.com/group/comp.lang.perl.misc comp.lang.perl.misc].|&lt;br /&gt;
Ширина=250px}}&lt;br /&gt;
&lt;br /&gt;
Языки сценариев стали так популярны потому, что ценой небольшого падения производительности они берут на себя такую скучную работу, как определение переменных, выделение памяти, возвращение её операционной системе и так далее. Придуманный в конце восьмидесятых Practical extraction and Report Language или Perl исходно предназначался для работы с большими объёмами текста. И хотя он не является самым популярным языком сценариев двадцать первого века, он остаётся лучшим инструментом для решения многих задач. Знаете ли вы, например, что Perl спас проект «Геном человека» (Human Genome Project)? Целиком эту историю можно прочитать по адресу: http://bioperl.org/GetStarted/tpj_ls_bio.html.&lt;br /&gt;
&lt;br /&gt;
В девяностые годы Perl получил широкое распространение, благодаря своему умению генерировать html-страницы. Сейчас эту нишу занял PHP, однако у Perl всё еще есть много поклонников, а так же большая база унаследованного кода, расширений (называемых модулями) и документации, которую легко приспособить для любых нужд.&lt;br /&gt;
&lt;br /&gt;
Вам вовсе не обязательно быть системным администратором или профессиональным программистом для того, чтобы получить пользу от этого языка. Perl может помочь, когда вам нужно быстро обработать текст или даже картинки. Независимо от того, находятся ли эти файлы на вашем жестком диске или в интернете, Perl обладает модулями, способными прозрачно работать и с тем, и с другим.&lt;br /&gt;
&lt;br /&gt;
=== Используй переменные, Люк! ===&lt;br /&gt;
Почти все основные правила синтаксиса Perl (такие как правила обрамления строк кавычками) очень напоминают или даже идентичны правилам оболочек Unix. Документации по оболочкам существует огромное количество, она не ограничивается учебником из предыдущих выпусков Linux Format. Поэтому, так как общую информацию можно найти в других местах, в эта серия сосредоточена на специфических особенностях языка, начиная с неудобочитаемых переменных. Я нежно люблю Perl, и использую его изо дня в день для решения самых разных задач. Но я должен предупредить вас: критики говорят, что это единственный язык, код на котором выглядит одинаково до и после&lt;br /&gt;
зашифровки. и если вы не знаете структуры программы на Perl, то так для вас и будет. Давайте рассмотрим компоненты этого языка. Первая вещь, которая раздражает новичков, когда они смотря на Perl-код — это тот факт, что все переменные имеют неалфавитный префикс. Клевещут, что из-за этого экран заполняется нечитаемым мусором. Но мне эти маркеры кажутся очень полезными, так как они сразу же сообщают о структуре соответствующей переменной и о том, что я могу сделать с нею. Вот пример:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;perl&amp;quot;&amp;gt;$NAMe = 'Johnny';&lt;br /&gt;
$AGE = 33;&lt;br /&gt;
@BOOK = ('Introduction', 'First Chapter', 'Second Chapter');&lt;br /&gt;
%STAR_WARS_FAMILY = ('Father', 'Anakin',&lt;br /&gt;
               'Mother', 'Padme',&lt;br /&gt;
               'Male twin', 'Luke',&lt;br /&gt;
               'Female twin', 'Leia');&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Первые две переменные — это скаляры. Скаляр Perl способен содержать один кусочек информации, будь то строка, число или ссылка. Их имена всегда начинаются с символа доллара ($). Строковые скаляры всегда заключаются в единичные('), двойные(&amp;quot;) или обратные кавычки(`), так же как и их эквиваленты из оболочек Unix, а числа, по аналогии, обходятся без кавычек.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$A = 'Hello';&lt;br /&gt;
$B = '$A Johnny!';&lt;br /&gt;
$C = &amp;quot;$A Johnny!&amp;quot;;&lt;br /&gt;
$D = `ls /usr/bin`;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Здесь переменная $b содержит именно то, что мы указали в коде, $C (благодаря двойным кавычкам) равняется «Hello Johnny!», а $D, поскольку для его значения использовались обратные кавычки, содержит результат выполнения команды ls /usr/bin/.&lt;br /&gt;
&lt;br /&gt;
Упорядоченный список скаляров, проиндексированный номерами, называется массивом и начинается с символа @. Он полезен для хранения чего-либо в последовательном порядке. Один элемент массива обозначается так: символ $, имя массива и номер элемента (начиная с 0) в квадратных скобках. В приведенном выше примере, второй элемент массива @book — это $book[1] и он равен «First Chapter».&lt;br /&gt;
&lt;br /&gt;
Ассоциативные массивы, или коротко говоря хэши (hash) — это последняя из основных категорий переменных языка Perl. Хэш — это группа скаляров, которые проиндексированы, или другими словам к которым можно обратиться не по номерам, а при помощи других скаляров, так называемых ключей. Другими словами, Perl позволяет сказать нам без излишних синтаксических конструкций, что в «семье звёздных войн»(STAR_WARS_FAMILY) отцом (Father) является Энакин (Anakin):$sTar_Wars_FamiLy{'Father'} = 'anakin'. Каждый ключ или значение хэша могут быть скаляром любого типа.&lt;br /&gt;
&lt;br /&gt;
Итак, даже самый короткий скрипт на Perl может быть заполнен символами $, @ и %. Но при этом мы можем создавать очень сложные структуры данных, используя минимальное количество префиксов, почти не заботясь об именовании, и при этом всегда понимая, каков смысл каждого кусочка. Это возможно благодаря мощной и немного опасной возможности вкладывать массивы и хэши друг в друга:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;perl&amp;quot;&amp;gt;%STAR_WARS_FAMILY = (&lt;br /&gt;
    'Father', {'Name', 'Anakin',&lt;br /&gt;
             'Height (cm)', 210,&lt;br /&gt;
             'jobs', ['Slave', 'Podracer pilot', 'Jedi Knight', 'Darth Vader']},&lt;br /&gt;
    'Mother', {} # другие такие же данные...&lt;br /&gt;
 );&lt;br /&gt;
 print &amp;quot;$STAR_WARS_FAMILY{'Father'}{'jobs'}[2]\n&amp;quot;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Это хэш, в котором каждый из элементов первого уровня является в свою очередь хэшем, содержащим элементы name (имя), Height (рост) and jobs (занятия), причём значением элемента jobs является массив. Обратите внимание, как мы различаем массивы и хэши при помощи квадратных и фигурных скобок, даже если они вложены друг в друга. В результате у нас получится, что оператор print в последней строке отобразит строчку Jedi knight (Джедай).&lt;br /&gt;
&lt;br /&gt;
Существует одна встроенная скалярная переменная, о которой вам надо знать. иногда программисты на Perl забывают указать, какую переменную они имели ввиду, например:&lt;br /&gt;
 print if условие&lt;br /&gt;
Эта инструкция указывает, что надо выполнять оператор print при некотором условии, но не говорит, что именно надо напечатать — значение какой переменной? В этом случае интерпретатор Perl использует текущее значение переменной по умолчанию, $_. Её значение определяются предыдущими выражениями, или она может выступать в качестве переменной цикла. Если вы помните об этой особенности, большое количество кода на Perl покажется вам гораздо понятнее.&lt;br /&gt;
&lt;br /&gt;
=== Помоги мне, Падме ===&lt;br /&gt;
Perl понимает большое число разных операторов. Некоторые из них применимы только к какому-то одному классу переменных, будь то скаляры, массивы или хэши, тогда как другие изменяют свой смысл в зависимости от того, к какой переменной они относятся. В этой статье осталось место только для нескольких вариантов. Основные числовые операторы имеют тот же смысл, что и в языке C.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
$A =10 * 7.5 - 16;&lt;br /&gt;
$B = $A % 4; # деление по модулю 4&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
и номера, и строки можно увеличивать при помощи оператора инкремента&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
$A = 4;&lt;br /&gt;
$B = 'ab';&lt;br /&gt;
$A++; # теперь $A равен 5...&lt;br /&gt;
$B++; # а $B равен 'ac'!!&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Не правда ли это здорово, что буквы тоже можно инкрементировать? Вы также можете соединять строки из нескольких частей:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
$FIRST_NAME = 'Luke';&lt;br /&gt;
$LAST_NAME = 'Skywalker';&lt;br /&gt;
$COMPLETE_NAME = $FIRST_NAME.' '.$LAST_NAME;&lt;br /&gt;
$REPEATED_NAME = $FIRST_NAME x 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Теперь $COMPLETE_NAME равняется «Luke Skywalker», a $REPEATED_NAME содержит «LukeLukeLuke».&lt;br /&gt;
&lt;br /&gt;
Скаляры можно сравнивать между собой многими разными способами. Давайте попробуем некоторые из них и посмотрим, что получится:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
$A &amp;lt; $B; # число $A больше, чем число $B?&lt;br /&gt;
$A lt $B; # строка $A располагается в словаре до $B?&lt;br /&gt;
$A &amp;lt;=&amp;gt; $B; # какое число меньше, $A или $B?&lt;br /&gt;
$A cmp $B; # какая строка располагается раньше, $A или $B?&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Некоторые сравнения имеют смысл, только если обе переменные являются или строками, или числами. Например, оператор 'Эта строка в алфавитном порядка стоит перед другой', всегда используется для сортировки в алфавитном порядке. Даже если одна или обе сравниваемые переменные содержат только числа, использование строковых операторов сравнения приведёт к сортировке в алфавитном порядке. Чтобы увидеть это в действии, введите следующую команду в командной строке и проверьте, какие из операторов сравнения вернут истину?.&lt;br /&gt;
  perl -e 'if (&amp;quot;dude&amp;quot; lt &amp;quot;hello&amp;quot;) {print &amp;quot;dude!\n&amp;quot;;} if (&amp;quot;dude&amp;quot; &amp;lt; &amp;quot;hello&amp;quot;) {print &amp;quot;Hello!\n&amp;quot;;}'&lt;br /&gt;
Фактически только первый тест должен завершиться успешно. Его смысл таков: «Верно ли, что строки переданы в алфавитном порядке?». Во втором операторе, используя &amp;lt; вместо lt, мы спрашиваем Perl, правда ли что число «dude» меньше числа «hello»? Конечно, это абсурдный вопрос, и ответ на него предсказуемо непредсказуемый.&lt;br /&gt;
&lt;br /&gt;
Еще одна особенность Perl, о которой стоит знать — это его постоянные преобразования строк в числа и обратно, в зависимости от контекста. Они могут быть огромным подспорьем или же постоянным источником недоразумений, в зависимости от того как часто вы забываете про это.&lt;br /&gt;
&lt;br /&gt;
Я думаю, что на этом достаточно разговоров про скалярные операторы. Когда речь заходит об операторах, работающих с массивами, Perl может сделать многое. Приведённый ниже пример показывает, как отдельный элемент может быть добавлен к массиву, а затем удалён оттуда:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
@Jedi = (&amp;quot;Yoda&amp;quot;, &amp;quot;Obi Wan&amp;quot;); # несколько рыцарей-джедаев&lt;br /&gt;
push(@Jedi, &amp;quot;Anakin&amp;quot;); # юный Энакин встаёт в строй&lt;br /&gt;
$gone_to_the_dark_side = pop(@Jedi); # Энакин уже не джедай&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Существуют специальные операторы для работы с хэшами. Инструкции, подобные следующим, встречаются в коде на Perl очень часто:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
while (($Actor, $Character) = each(%STAR_WARS_CAST));&lt;br /&gt;
# или даже&lt;br /&gt;
@ACTORS_ONLY = keys(%STAR_WARS_CAST);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Первая строка будет циклически перебирать элементы хэша %STAR_WARS_CAST, каждый раз присваивая ключ очередного элемента и его значение паре скаляров $Actor и $Character, которые вы затем можете обработать, как вам захочется. Оператор key используется в том случае, когда нужно сохранить только ключи хэша в отдельном массиве и работать с ними независимо от значений.&lt;br /&gt;
&lt;br /&gt;
В Perl существует ещё очень много операторов, но у меня не осталось места для их описания. Однако того, что мы уже успели рассмотреть, с лихвой хватит для понимания структуры простого сценария. Свою силу и истинную ценность Perl особенно ярко проявляет в работе с массивами и хэшами.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Учебники]]&lt;br /&gt;
[[Категория:Первые шаги]]&lt;br /&gt;
[[Категория:Perl]]&lt;/div&gt;</summary>
		<author><name>Говно</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Lockal</id>
		<title>Обсуждение участника:Lockal</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Lockal"/>
				<updated>2008-06-18T17:02:55Z</updated>
		
		<summary type="html">&lt;p&gt;Говно: «Обсуждение участника:Lockal» переименована в «Обсуждение участника:Говно»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Сэр, я хоть и с опозданием (не было нета), но приступил к работе.&lt;br /&gt;
Спасибо, конечно, за помощь, но этот номер зарегистрирован за мной.&lt;br /&gt;
: Без проблем, хотя я начал[http://wiki.linuxformat.ru/index.php?title=LXF85&amp;amp;action=history] работать над номером, когда он был ещё свободен[http://wiki.linuxformat.ru/?oldid=623]. А пока я займусь другими номерами. --[[Участник:Lockal|Lockal]] 19:16, 16 марта 2008 (MSK)&lt;br /&gt;
&lt;br /&gt;
Не хочу показаться интервентом - могу переслать письмо от Валентина Синицына от 6 марта, где за мной утвердили 85-ый номер. --[[Участник:flagist0|flagist0]]&lt;br /&gt;
&lt;br /&gt;
'''LXF84''' Спасибо за статью по LaTeX, но этот номер (LXF 84) занят, и я хотел бы завершить работу над ним самостоятельно&lt;br /&gt;
[[Участник:Skryabin yuri|Skryabin yuri]]&lt;/div&gt;</summary>
		<author><name>Говно</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Lockal</id>
		<title>Участник:Lockal</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Lockal"/>
				<updated>2008-06-18T17:02:55Z</updated>
		
		<summary type="html">&lt;p&gt;Говно: «Участник:Lockal» переименована в «Участник:Говно»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Учебники ===&lt;br /&gt;
* [[LXF70:Gnome 2.10]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Perl}}&lt;br /&gt;
* [[LXF70:Perl. Переменные и операторы]]&lt;br /&gt;
* [[LXF70:Perl. Сортируем наш код]]&lt;br /&gt;
* [[LXF72:Perl]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF70:Subversion1]]&lt;br /&gt;
* [[LXF70:Subversion2]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF70:PHP. Загадка Монти Холла]]&lt;br /&gt;
* [[LXF73:PHP I]]&lt;br /&gt;
* [[LXF73:PHP II]]&lt;br /&gt;
* [[LXF76:Учебник PHP]]&lt;br /&gt;
* [[PHP]]&lt;br /&gt;
* [[LXF78:Учебник PHP: MySQL 5.0 Special]]&lt;br /&gt;
* [[LXF79:PHP]]&lt;br /&gt;
* [[LXF80:PHP]]&lt;br /&gt;
* [[LXF81:PHP]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Gambas}}&lt;br /&gt;
* [[LXF71:Gambas]]&lt;br /&gt;
* [[LXF72:Gambas]]&lt;br /&gt;
* [[LXF73:Gambas]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF70:GIMP. Коррекция улыбки]]&lt;br /&gt;
* [[LXF72:GIMP]]&lt;br /&gt;
* [[LXF73:GIMP]]&lt;br /&gt;
* [[LXF76:Учебник Gimp, часть 1]]&lt;br /&gt;
* [[LXF76:Учебник Gimp, часть 2]]&lt;br /&gt;
* [[LXF78:Gimp: Блики на стекле]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF73:Автомонтирование USB]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF73:Русификация Debian 3.1]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF73:Локализация ПО]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF72:Первые шаги]]&lt;br /&gt;
* [[LXF73:Первые шаги]]&lt;br /&gt;
* [[LXF76:Первые шаги: Writer]]&lt;br /&gt;
* [[LXF76:Первые шаги: Impress]]&lt;br /&gt;
* [[LXF80:первые шаги]]&lt;br /&gt;
* [[LXF81:Firefox]]&lt;br /&gt;
* [[LXF82:Первые шаги]]&lt;br /&gt;
* [[LXF83:Ubuntu_for_children]]&lt;br /&gt;
* [[LXF84:Первые шаги]]&lt;br /&gt;
* [[LXF89:Первые шаги]]&lt;br /&gt;
* [[LXF92:Первые шаги]]&lt;br /&gt;
* [[LXF96:Первые шаги]]&lt;br /&gt;
* [[LXF97:Первые шаги]]&lt;br /&gt;
* [[LXF98:Первые_шаги]]&lt;br /&gt;
* [[LXF99:Первые шаги]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF76:Азбука записи]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF76:Учебник Fuse]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF76:Ubuntu по-русски]]&lt;br /&gt;
* [[LXF76:Учебник Ubuntu, часть 2]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Inkscape}}&lt;br /&gt;
* [[LXF76:Учебник Inkscape, часть 1]]&lt;br /&gt;
* [[LXF76:Учебник Inkscape, часть 2]]&lt;br /&gt;
* [[LXF78:Inkscape. Работа с текстом]]&lt;br /&gt;
* [[LXF79:Inkscape]]&lt;br /&gt;
* [[LXF81:Inkscape]]&lt;br /&gt;
* [[LXF82:Inkscape]]&lt;br /&gt;
* [[LXF83:InkScape]]&lt;br /&gt;
* [[LXF84:Inkscape]]&lt;br /&gt;
* [[LXF85:Inkscape]]&lt;br /&gt;
* [[LXF86:Inkscape]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/MetaPost}}&lt;br /&gt;
* [[LXF76:MetaPost]]&lt;br /&gt;
* [[LXF77:MetaPost]]&lt;br /&gt;
* [[LXF78:MetaPost]]&lt;br /&gt;
* [[LXF79:MetaPost]]&lt;br /&gt;
* [[LXF80:MetaPost]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Python}}&lt;br /&gt;
* [[LXF76:Уроки Python, часть 2]]&lt;br /&gt;
* [[LXF76:Разработка расширений Pyhton]]&lt;br /&gt;
* [[LXF78:Уроки Python]]&lt;br /&gt;
* [[LXF79:Python]]&lt;br /&gt;
* [[LXF80:Python]]&lt;br /&gt;
* [[LXF81:Python]]&lt;br /&gt;
* [[LXF82:Python]]&lt;br /&gt;
* [[LXF83:Python]]&lt;br /&gt;
* [[LXF84:Python]]&lt;br /&gt;
* [[LXF97:Python]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF76:Hardcore Linux, часть 1]]&lt;br /&gt;
* [[LXF76:Hardcore Linux, часть 2]]&lt;br /&gt;
* [[LXF78:Мощные инструменты командной строки]] ?&lt;br /&gt;
* [[LXF79:Hardcore Linux]]&lt;br /&gt;
* [[LXF80:Hardcore Linux]]&lt;br /&gt;
* [[LXF82:Hardcore Linux]]&lt;br /&gt;
* [[LXF83:Hardcore_Linux]]&lt;br /&gt;
* [[LXF84:Hardcore Linux]]&lt;br /&gt;
* [[LXF89:Hardcore Linux]]&lt;br /&gt;
* [[LXF92:Hardcore Linux]]&lt;br /&gt;
* [[LXF94:Графическое web-приложение]]&lt;br /&gt;
* [[LXF96:Hardcore linux:APT]]&lt;br /&gt;
* [[LXF97:Hardcore Linux]]&lt;br /&gt;
* [[LXF98:Hardcore Linux]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF78:Evolution: Управляйте своей почтой]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Qt/KDE}}&lt;br /&gt;
* [[LXF78:Знакомство с Qt: первые шаги]]&lt;br /&gt;
* [[LXF79:Qt/KDE]]&lt;br /&gt;
* [[LXF80:Qt/KDE]]&lt;br /&gt;
* [[LXF81:KDE]]&lt;br /&gt;
* [[LXF82:Qt/KDE]]&lt;br /&gt;
* [[LXF83:Qt_KDE]]&lt;br /&gt;
* [[LXF84:Qt/KDE]]&lt;br /&gt;
* [[LXF85:Qt/KDE]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF78:Почему – Vim?]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF79:Audacity]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF79:Чистим записи]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF79:DCOP]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/OOo Basic}}&lt;br /&gt;
* [[LXF80:OOo Basic]]&lt;br /&gt;
* [[LXF81:OOo]]&lt;br /&gt;
* [[LXF82:OpenOffice.org]]&lt;br /&gt;
* [[LXF83:OOo_Basic]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF84:OpenOffice.org]]&lt;br /&gt;
* [[LXF85:OpenOffice.org Base]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF82:Безопасность]]&lt;br /&gt;
* [[LXF84:Безопасность]]&lt;br /&gt;
* [[LXF85:Безопасность]]&lt;br /&gt;
* [[LXF86:Безопасность]]&lt;br /&gt;
* [[LXF89:Безопасность]] 5&lt;br /&gt;
&lt;br /&gt;
* [[LXF80:загрузка]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Unix API}}&lt;br /&gt;
* [[LXF80:Программирование для Linux]]&lt;br /&gt;
* [[LXF81:IPC]]&lt;br /&gt;
* [[LXF82:Unix API]]&lt;br /&gt;
* [[LXF83:Unix_API]]&lt;br /&gt;
* [[LXF84:Unix API]]&lt;br /&gt;
* [[LXF85:Unix API]]&lt;br /&gt;
* [[LXF86:Unix]]&lt;br /&gt;
* [[LXF89:Unix API]] 8&lt;br /&gt;
* [[LXF90:Unix API]]&lt;br /&gt;
* [[LXF91:Unix API]]&lt;br /&gt;
* [[LXF92:Unix API]] 12&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF80:шифрование]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF81:WordPress]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF81:DansGuardian]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF81:Open-Xchange]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Maxima}}&lt;br /&gt;
* [[LXF81:Maxima]]&lt;br /&gt;
* [[LXF82:Maxima]]&lt;br /&gt;
* [[LXF83:MAXIMA]]&lt;br /&gt;
* [[LXF84:Maxima]]&lt;br /&gt;
* [[LXF85:Maxima]]&lt;br /&gt;
* [[LXF86:Maxima]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF81:PAW]]&lt;br /&gt;
* [[LXF83:ROOT]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF82:Разработка 3D-игры]]&lt;br /&gt;
* [[LXF83:3D_Game]]&lt;br /&gt;
* [[LXF84:Разработка 3D-игры]]&lt;br /&gt;
* [[LXF85:Ogre]]&lt;br /&gt;
* [[LXF86:Ogre]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/LaTeX}}&lt;br /&gt;
* [[LXF82:LaTeX]]&lt;br /&gt;
* [[LXF83:LaTex]]&lt;br /&gt;
* [[LXF84:LaTeX]]&lt;br /&gt;
* [[LXF85:LaTeX]]&lt;br /&gt;
* [[LXF86:LaTeX]]&lt;br /&gt;
* [[LXF89:LaTeX]] 6&lt;br /&gt;
* [[LXF90:LaTeX]]&lt;br /&gt;
* [[LXF91:LaTeX]]&lt;br /&gt;
* [[LXF92:TeX]] 9&lt;br /&gt;
* [[LXF94:LaTeX Программирование]]&lt;br /&gt;
* [[LXF97:TeX]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Java}}&lt;br /&gt;
* [[LXF82:Java]]&lt;br /&gt;
* [[LXF84:Java]]&lt;br /&gt;
* [[LXF85:Java]]&lt;br /&gt;
* [[LXF86:Java]]&lt;br /&gt;
* [[LXF87/88:Java]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Java EE}}&lt;br /&gt;
* [[LXF89:Java EE]] 1&lt;br /&gt;
* [[LXF90:JavaEE]]&lt;br /&gt;
* [[LXF91:Java EE]]&lt;br /&gt;
* [[LXF92:Java EE]] 4&lt;br /&gt;
* [[LXF94:Команды и фабрики]] (серия «Java Enterprise Edition»)&lt;br /&gt;
* [[LXF95:Java EE]]&lt;br /&gt;
* [[LXF96:Java EE]] 8&lt;br /&gt;
* [[LXF97:Java]]&lt;br /&gt;
* [[LXF98:Java EE10]] 10&lt;br /&gt;
* [[LXF99:Java EE EJB3]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF83:HDD]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF83:XDMCP]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF83:WINK]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF85:Compiz]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/PostgreSQL}}&lt;br /&gt;
* [[LXF85:PostgreSQL]]&lt;br /&gt;
* [[LXF86:Учебники:PostgreSQL]]&lt;br /&gt;
* [[LXF89:PostgreSQL]] 4&lt;br /&gt;
* [[LXF90:PostgreSQL]]&lt;br /&gt;
* [[LXF91:PostgreSQL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF86:Wine]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF86:Kamaelia]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/GTK+}}&lt;br /&gt;
* [[LXF86:GTK]]&lt;br /&gt;
* [[LXF89:GTK+]] 3&lt;br /&gt;
* [[LXF90:GTK+]]&lt;br /&gt;
* [[LXF91:GTK]]&lt;br /&gt;
* [[LXF92:GTK+]] 6&lt;br /&gt;
* [[LXF94:GTK+: Буфер обмена и VFS]]&lt;br /&gt;
* [[LXF95:GTK+]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Blender}}&lt;br /&gt;
* [[LXF89:Blender]] 2&lt;br /&gt;
* [[LXF90:Blender]]&lt;br /&gt;
* [[LXF91:Blender]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF90:RPM]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF90:SugarCRM]]&lt;br /&gt;
* [[LXF91:SugarCRM]]&lt;br /&gt;
* [[LXF92:SugarCRM]] 3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF90:Grub]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF91:Система]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF91:XSLT]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Mono}}&lt;br /&gt;
* [[LXF89:Mono]]&lt;br /&gt;
* [[LXF90:Mono]]&lt;br /&gt;
* [[LXF91:Mono]]&lt;br /&gt;
* [[LXF92:Mono-Мания]]&lt;br /&gt;
* [[LXF94:Программирование для Mono]]&lt;br /&gt;
* [[LXF95:Mono]]&lt;br /&gt;
* [[LXF96:Mono-мания]]&lt;br /&gt;
* [[LXF97:Mono]]&lt;br /&gt;
* [[LXF98:Mono]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF91:Deb]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF92:Lm-sensors HOWTO]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Cinelerra}}&lt;br /&gt;
* [[LXF92:Cinelerra]] 1&lt;br /&gt;
* [[LXF93:Cinelerra]]&lt;br /&gt;
* [[LXF94:Cinelerra]]&lt;br /&gt;
* [[LXF95:Cinelerra]]&lt;br /&gt;
* [[LXF96:Cinelerra]] 5&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF94:Обмен файлами]] (серия «Linux для новичков»)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF94:Макрос, загружающий данные]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF94:Следим за сетью]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF95:F-Spot]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF95:Akelos]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF95:Cron]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF95:DCOP]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Препринт}}&lt;br /&gt;
* [[LXF95:Препринт]]&lt;br /&gt;
* [[LXF96:Препринт]]&lt;br /&gt;
* [[LXF97:Препринт]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF96:Bash]] 1&lt;br /&gt;
* [[LXF97:Bash]]&lt;br /&gt;
* [[LXF98:Bash3]] 3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF96:Evolution]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF96:Vim]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Командная строка]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:GtkSourceView]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Новая серия!]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Hibernate]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:KDE]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:Диагностика]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:Ананас3]] 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:wxWidgets1]] 1&lt;br /&gt;
* [[LXF99:wxWidgets]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:Perl и C++]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:Чистка DVD видео]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF99:D-Bus]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF99:WavPack]]&lt;/div&gt;</summary>
		<author><name>Говно</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF76:GIMP1</id>
		<title>LXF76:GIMP1</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF76:GIMP1"/>
				<updated>2008-06-18T17:02:40Z</updated>
		
		<summary type="html">&lt;p&gt;Говно: «LXF76:Gimp1» переименована в «Говно 1»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Gimp Инструменты выделения ===&lt;br /&gt;
'''''Майкл Хэммел''' (Michael J Hammel) сравнивает новейшее средство Foreground Selection с достопочтенным Quick Mask.&lt;br /&gt;
''&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img_76_78_1.jpg|left|thumb|From a wormhole in deep space (well, LXF73), I showed you how to create animated fractals. If you missed the issue, call 0870 8374773 or +44 1858 438795.]]&lt;br /&gt;
&lt;br /&gt;
В мире свободного ПО свой отсчет времени; проект Gimp - не исключение. Недавно разнесся слух о скором выходе&lt;br /&gt;
новейшей версии, Gimp 2.4. Действительно ли грядет это событие, пока не ясно. Несомненно одно - в арсенале Gimp, среди прочих новинок, появится любопытный инструмент Foreground Selection - интегрированная версия сравнительно нового модуля SIOX для Gimp&lt;br /&gt;
2.2. &lt;br /&gt;
&lt;br /&gt;
Проект SIOX (Simple Interactive Object eXtraction - Простая интерактивная выемка объектов) предусматривает создание ПО для упрощения процесса отделения объектов на рисунках от их окружения (графической выборки). Gimp уже обладает средствами для решения этой весьма востребованной задачи - именно для нее был создан инструмент Scissors, Ножницы. Действует он сравнительно неплохо, но&lt;br /&gt;
быстрым его не назовешь: выборка сложных графических объектов&lt;br /&gt;
требует назначения большого количества контрольных точек, а редактировать эти точки не так-то просто. Зато, вооружившись терпением&lt;br /&gt;
и временем, вы получите отменно точную вырезку.&lt;br /&gt;
&lt;br /&gt;
Для той же цели предназначен еще один инструмент - Quick&lt;br /&gt;
Mask. Точность вырезки при работе с ним ограничена единственно&lt;br /&gt;
вашей способностью аккуратно очертить контур. Пользоваться Quick&lt;br /&gt;
Mask проще, чем Scissors, поскольку можно переключаться между&lt;br /&gt;
маской и вырезкой и уточнять ее. В принципе, очертить контур намного&lt;br /&gt;
легче, чем назначать уйму контрольных точек.&lt;br /&gt;
&lt;br /&gt;
Итак, инструментов для графической выборки хватает. Почему тогда мы говорим о появлении новых? Да потому, что разработчики Gimp&lt;br /&gt;
постоянно ищут способы усовершенствования программы. Вы спросите, не станет ли Foreground Selection одним из таких улучшений?&lt;br /&gt;
В процессе урока я как раз и собираюсь ответить на этот вопрос. Я буду сравнивать простоту использования Foreground Selection&lt;br /&gt;
и Quick Mask и доступную для них точность вырезки при работе в комбинации с другими средствами Gimp. Объектами послужат&lt;br /&gt;
несколько образцовых изображений. Следуя за мной, шаг за шагом, вы незаметно для себя освоите ценные технологии графической&lt;br /&gt;
выборки!&lt;br /&gt;
&lt;br /&gt;
==== Часть 1 - простое выделение на однотонном фоне ====&lt;br /&gt;
&lt;br /&gt;
Чтобы сравнить инструменты Foreground Select и Fuzzy Select из инструментария Gimp 2.2, поработаем с изображением розы на белом фоне.&lt;br /&gt;
&lt;br /&gt;
===== Как работает Fuzzy Select =====&lt;br /&gt;
{{Врезка|right|&lt;br /&gt;
|Заголовок=ПОДСКАЗКА&lt;br /&gt;
|Содержание=* Пользуясь Quick Mask, можно сколько угодно раз переключаться между маской и вырезкой для подчистки. Ни один известный инструмент не дает такой простоты и свободы для этой операции, даже новейший Foreground Select.&lt;br /&gt;
* Для отмены сделанной вами выборки воспользуйтесь стандартным откатом [Ctrl]+[Z], попробуйте изменить настройку инструмента, затем начните сначала. Такая возможность есть у любого средства выборки, исключая Quick Mask (которому для подчистки просто не нужна настройка параметров).&lt;br /&gt;
* Когда вы отпустите кнопку мыши, Foreground Select немедленно обновит вашу вырезку. Поэтому не отпускайте кнопку, пока не закрасите большую часть нужного вам объекта. Для подчистки можно неоднократно возобновлять закрашивание.&lt;br /&gt;
* Когда вы закрасите вырезку, поместите курсор в окно изображения и нажмите клавишу ввода. Синее пространство превратится в реальную выборку.&lt;br /&gt;
|Ширина=150px}}&lt;br /&gt;
&lt;br /&gt;
Инструмент Fuzzy Select (по виду напоминающий волшебную палочку) выделяет смежные точки, попадающие в определенный диапазон.&lt;br /&gt;
Превосходный способ отделить от рисунка практически монотонный фон!&lt;br /&gt;
[[Image:Img_76_79_1.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
===== Параметры Fuzzy Select =====&lt;br /&gt;
&lt;br /&gt;
Параметр Threshold - Порог - в диалоговом окне настройки определяет предварительный контур. Чем выше порог, тем точнее вырезка.&lt;br /&gt;
В нашем примере было установлено значение порога 25,0. После щелчка мышью на фоновом участке получилась приличная, хотя и не идеальная, вырезка.&lt;br /&gt;
[[Image:Img_76_79_2.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
===== Повышение порога =====&lt;br /&gt;
&lt;br /&gt;
Решив подобраться к розе поближе, я отменил выделение (Ctrl+Z) и повысил порог до 75,0. Затем оценил результат. Последняя попытка с порогом 105,0 дала отличную вырезку - вот уж поистине метод проб и ошибок! Чтобы вместо фона выделить розу, я инвертировал выделение (Select &amp;gt; Invert - Выделение &amp;gt; Инвертировать).&lt;br /&gt;
[[Image:Img_76_79_3.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
===== Как работает Foreground Selection =====&lt;br /&gt;
&lt;br /&gt;
Значок Foreground Selection на панели инструментов Gimp имеет вид человеческой фигурки, окаймленной контуром из точек. В диалоговом&lt;br /&gt;
окне Tool Options - Параметры инструмента - есть два интересующих нас элемента управления: кнопки смены выделения объекта/фона&lt;br /&gt;
(Mark Foreground/Background) и ползунок изменения размера кисти.&lt;br /&gt;
[[Image:Img_76_79_4.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
===== Делаем приблизительное выделение =====&lt;br /&gt;
&lt;br /&gt;
При выборке с помощью Foreground Selection нужно предварительно очертить мышью выбираемый объект в окне программы. Указатель&lt;br /&gt;
мыши будет выглядеть точно так же, как в инструменте Free Select - Свободное выделение. Щелкаем и обводим рукой контур вокруг нужного нам объекта - разрешается выходить за пределы окна изображения, чтобы руке было удобнее.&lt;br /&gt;
[[Image:Img_76_79_5.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
===== Уточнение выделения =====&lt;br /&gt;
&lt;br /&gt;
По умолчанию кнопка смены выделения объекта/фона стоит в положении Mark Foreground - Выделение объекта, я не стал его менять.&lt;br /&gt;
Кисть не должна быть толще стебелька розы внизу изображения. Цвет кисти я выбрал зеленым, для большей наглядности следующего шага.&lt;br /&gt;
Теперь закрасим кистью розу вместе со стеблем.&lt;br /&gt;
[[Image:Img_76_80_1.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
===== Вторая попытка с Mark Background =====&lt;br /&gt;
&lt;br /&gt;
Я не сумел захватить весь стебель розы! Однако я попробовал выбрать розу непосредственно с помощью Foreground Select, выделив фон&lt;br /&gt;
инструментом Fuzzy Select. Во второй попытке после проведения Free Select (Свободной выборки) я включил выделение фона (Mark Background), потом закрашивал только белые участки.&lt;br /&gt;
[[Image:Img_76_80_2.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
===== Настройка чувствительности =====&lt;br /&gt;
&lt;br /&gt;
Понятно, что результат обязан быть значительно лучше, поэтому я пробовал снова и снова, при помощи ручной выборки и выделения фона&lt;br /&gt;
(Mark Background). Затем я включил параметр Feather - Сглаживание - и сдвинул все три ползунка регулировки чувствительности (Sensitivity) до отказа вправо. Как видите, качество вырезки значительно повысилось, но можно улучшить и этот результат, сузив&lt;br /&gt;
выделение на 1-2 пикселя перед вырезанием и вставкой.&lt;br /&gt;
[[Image:Img_76_80_3.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
Результат для этого конкретного изображения нельзя признать хорошим. Быстрая и грубая работа с Foreground Select давала некачественное выделение, пока я не взялся за настройку чувствительности. Для такого простого случая Fuzzy Select следует признать более быстрым и точным средством.&lt;br /&gt;
&lt;br /&gt;
==== Часть 2 - выделение изображения на сложном фоне ====&lt;br /&gt;
&lt;br /&gt;
С простой задачей Fuzzy Select справился лучше. Теперь посмотрим, кто победит при работе с более сложным изображением.&lt;br /&gt;
&lt;br /&gt;
===== Берем Quick Mask =====&lt;br /&gt;
&lt;br /&gt;
Картинка здесь посложнее, зато мячи проще вырезать. На успех Fuzzy Select рассчитывать не приходится: мячи лежат чересчур близко друг&lt;br /&gt;
к другу. Вдобавок они не очень-то отличаются по цвету от фона и от ракетки. Вероятно, Quick Mask из набора инструментов версии 2.2 будет лучшим выбором.&lt;br /&gt;
[[Image:Img_76_80_4.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
===== Закрашиваем вырезку =====&lt;br /&gt;
&lt;br /&gt;
Нажмите кнопку Quick Mask. Ваше изображение примет красный оттенок, кнопка тоже покраснеет. Красное пространство в выделение не&lt;br /&gt;
попадет. Перекрасьте кистью (Paintbrush) участок, который хотите&lt;br /&gt;
выделить, предварительно сделав цвет краски (Foreground) белым - нажмите [D] (цвета по умолчанию) и [X] (инвертировать цвета).&lt;br /&gt;
[[Image:Img_76_80_5.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
===== Вставляем в другой слой =====&lt;br /&gt;
&lt;br /&gt;
Оценим выделение, скопировав объект и вставив его в новый слой. На контрастном черном фоне виднее контур мяча. Для редактирования&lt;br /&gt;
выделения вернем маску на место (Layer &amp;gt; Alpha To Selection - Слой &amp;gt; Прозрачность в выделение), возвратимся в первоначальный слой, включим Quick Mask и закрасим заново.&lt;br /&gt;
[[Image:Img_76_81_1.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
===== Проба SIOX =====&lt;br /&gt;
&lt;br /&gt;
Foreground Select в Gimp 2.4 работает немного лучше, но постоянно прихватывает лишние участки. Рисунок запечатлел четыре разные&lt;br /&gt;
попытки работы с этим инструментом. В последней из них удалось показать ворс на мячике - для Quick Mask подобное почти невозможно.&lt;br /&gt;
[[Image:Img_76_81_2.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
===== Играем с картинками =====&lt;br /&gt;
{{Врезка|right|&lt;br /&gt;
|Заголовок=CREDIT TO...&lt;br /&gt;
|Содержание=Images used in this tutorial are from http://www.BigStockPhoto.com and the free collection at http://PDPhoto.org.&lt;br /&gt;
|Ширина=150px}}&lt;br /&gt;
&lt;br /&gt;
Перебрав еще несколько изображений, я нашел то, в котором, на мой взгляд, Foreground Select проявил себя очень неплохо. Однако разработчики SIOX говорят, что при работе в режиме Mark Foreground, нежелательно, чтобы пиксели фона и вырезки имели сходные цвета.&lt;br /&gt;
В случае выделения кофе в чашке могут возникнуть проблемы.&lt;br /&gt;
[[Image:Img_76_81_3.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
===== Выделение фона =====&lt;br /&gt;
&lt;br /&gt;
Как обычно, выбираемый объект очерчивается по контуру от руки. Я провел черту, начав ее вне окна изображения, снизу вправо, и вывел ее снова в окно справа наверху. Затем я закрасил чашку широкой кистью со сглаживающим фактором четыре. В вырезку попал только&lt;br /&gt;
маленький кусочек фона, слева внизу.&lt;br /&gt;
[[Image:Img_76_81_4.PNG|center]]&lt;br /&gt;
&lt;br /&gt;
===== Уточнение выделения =====&lt;br /&gt;
&lt;br /&gt;
Включите выделение фона (Mark Background) и закрасьте нежелательные участки фона для их удаления. Quick Mask могла бы сгладить ободок чашки так же быстро.&lt;br /&gt;
[[Image:Img_76_81_5.png|center]]&lt;br /&gt;
&lt;br /&gt;
==== Подведем итоги ====&lt;br /&gt;
&lt;br /&gt;
Итак, что же дает сравнение двух средств, старого и нового? В нынешнем виде Foreground Selection не особо упрощает задачу&lt;br /&gt;
извлечения объекта из изображения, по сравнению с существующими инструментами. С другой стороны, изображения бывают разные,&lt;br /&gt;
и иметь несколько инструментов для разных задач отнюдь не повредит.&lt;br /&gt;
&lt;br /&gt;
Поймите меня правильно, я не отрицаю, что Foreground Select имеет значительный потенциал. Обратите внимание, что в случае&lt;br /&gt;
с изображением чашки кофе (там, где программа смогла блеснуть способностями) я сделал вырезку меньше чем за минуту. Но отнюдь не&lt;br /&gt;
очевидно, где почва для наилучшего применения программы. Инструмент может делать хотя и не идеальную, но очень хорошую&lt;br /&gt;
выборку. Весьма способствует результату работа над параметрами. И не забудьте, что ко времени официального выхода версии 2.4 инструмент Foreground Selection может реально измениться (я пользовался версией Gimp 2.3.4 для разработчиков) - не спешите соглашаться с моей критикой.&lt;/div&gt;</summary>
		<author><name>Говно</name></author>	</entry>

	</feed>