Простой Python — страница 65 из 66

Так выглядит сервер, poem_pub.py, который отщипывает по одному слову стихотворения и публикует его в тему vowels, если оно начинается с гласной, и в тему five, если состоит из пяти букв. Некоторые слова могут оказаться в обеих темах, некоторые — ни в одной:

import string

import zmq

host = '127.0.0.1'

port = 6789

ctx = zmq.Context()

pub = ctx.socket(zmq.PUB)

pub.bind('tcp://%s:%s' % (host, port))

with open('mammoth.txt', 'rt') as poem:

····words = poem.read()

for word in words.split():

····word = word.strip(string.punctuation)

····data = word.encode('utf-8')

····if word.startswith(('a','e','i','o','u','A','e','i','o','u')):

········pub.send_multipart([b'vowels', data])

····if len(word) == 5:

········pub.send_multipart([b'five', data])

Клиент poem_sub.py подписывается на темы vowels и five и выводит на экран тему и слово:

import string

import zmq

host = '127.0.0.1'

port = 6789

ctx = zmq.Context()

sub = ctx.socket(zmq.SUB)

sub.connect('tcp://%s:%s' % (host, port))

sub.setsockopt(zmq.SUBSCRIBE, b'vowels')

sub.setsockopt(zmq.SUBSCRIBE, b'five')

while True:

····topic, word = sub.recv_multipart()

····print(topic, word)

Если вы запустите эти программы, они не будут работать, хотя код выглядит хорошо. Вам нужно прочитать руководство ZeroMQ, чтобы узнать о проблеме медленного присоединившегося: даже если вы запустите клиент раньше сервера, сервер начнет отправлять данные сразу после запуска, а клиенту потребуется некоторое время, чтобы подключиться к серверу. Если вы публикуете сообщения постоянным потоком и не задумываетесь о том, когда к вам подключаются подписчики, это не проблема. Но в этом случае поток данных настолько короткий, что он заканчивается еще до того, как подписчик успеет моргнуть.

Простейший способ исправить это — заставить публикатора пропустить секунду после вызова метода bind() и до того, как он начнет отправлять сообщения. Назовем эту версию poem_pub_sleep.py:

import string

import zmq

from time import sleep

host = '127.0.0.1'

port = 6789

ctx = zmq.Context()

pub = ctx.socket(zmq.PUB)

pub.bind('tcp://%s:%s' % (host, port))

sleep(1)

with open('mammoth.txt', 'rt') as poem:

····words = poem.read()

for word in words.split():

····word = word.strip(string.punctuation)

····data = word.encode('utf-8')

····if word.startswith(('a','e','i','o','u','A','e','i','o','u')):

········print('vowels', data)

········pub.send_multipart([b'vowels', data])

····if len(word) == 5:

········print('five', data)

········pub.send_multipart([b'five', data])

Запустите подписчика, а затем и сонного публикатора:

$ python poem_sub.py

$ python poem_pub_sleep.py

Теперь у подписчика есть время на то, чтобы получить сообщения по выбранным темам. Так выглядят первые строки выходной информации:

b'five' b'queen'

b'vowels' b'of'

b'five' b'Lying'

b'vowels' b'at'

b'vowels' b'ease'

b'vowels' b'evening'

b'five' b'flies'

b'five' b'seize'

b'vowels' b'All'

b'five' b'gaily'

b'five' b'great'

b'vowels' b'admired'

Если вы не можете добавить вызов sleep() в код публикатора, вы можете синхронизировать публикатора и подписчика с помощью сокетов REQ и REP. Примеры файлов publisher.py и subscriber.py вы можете найти на GitHub.

Приложение Е. Вспомогательные таблицы

Я обнаружил, что некоторые вещи мне приходится подсматривать слишком часто. Вот несколько таблиц, которые, надеюсь, окажутся вам полезны.

Приоритет операторов

Эта таблица — ремикс официальной документации о приоритетах для Python 3, операторы с самым высоким приоритетом находятся наверху.

ОператорОписание и примеры
[v1, …], { v1, …}, { k1: v1, …}, (…)Создание или включение списка/множества/словаря/генератора, выражение в скобках
seq [n], seq [n: m], func (args…), obj.attrИндекс, разбиение, вызов функции, ссылка на атрибут
**Экспонента
'+'x, '-'x, '~'xЗнаки «плюс» и «минус», битовое НЕ
*, /, //, %Умножение, деление с плавающей точкой, целочисленное деление, напоминание
+, -Сложение, вычитание
<<, >>Битовый сдвиг вправо или влево
&Битовое И
|Битовое ИЛИ
in, not in, is, is not, <, <=, >, >=,!=, ==Проверка на членство и равенство
not xБулево (логическое) НЕ
andБулево И
orБулево ИЛИ
if … elseУсловное выражение
lambdaЛямбда-выражение

Строковые методы

Python предлагает строковые методы (могут быть использованы с любым объектом str) и модуль string, содержащий полезные определения. Воспользуемся проверочными переменными:

>>> s = "OH, my paws and whiskers!"

>>> t = "I'm late!"

Изменение регистра

>>> s.capitalize()

'Oh, my paws and whiskers!'

>>> s.lower()

'oh, my paws and whiskers!'

>>> s.swapcase()

'oh, MY PAWS AND WHISKERS!'

>>> s.title()

'Oh, My Paws And Whiskers!'

>>> s.upper()

'OH, MY PAWS AND WHISKERS!'

Поиск

>>> s.count('w')

2

>>> s.find('w')

9

>>> s.index('w')

9

>>> s.rfind('w')

16

>>> s.rindex('w')

16

>>> s.startswith('OH')

True

Изменение

>>> ''.join(s)

'OH, my paws and whiskers!'

>>> ' '.join(s)

'O H,···m y···p a w s···a n d···w h i s k e r s!'

>>> ' '.join((s, t))

"OH, my paws and whiskers! I'm late!"

>>> s.lstrip('HO')

', my paws and whiskers!'

>>> s.replace('H', 'MG')

'OMG, my paws and whiskers!'

>>> s.rsplit()

['OH,', 'my', 'paws', 'and', 'whiskers!']

>>> s.rsplit(' ', 1)

['OH, my paws and', 'whiskers!']

>>> s.split()

['OH,', 'my', 'paws', 'and', 'whiskers!']

>>> s.split(' ')

['OH,', 'my', 'paws', 'and', 'whiskers!']

>>> s.splitlines()

['OH, my paws and whiskers!']

>>> s.strip()

'OH, my paws and whiskers!'

>>> s.strip('s!')

'OH, my paws and whisker'

Форматирование

>>> s.center(30)

'··OH, my paws and whiskers!···'

>>> s.expandtabs()

'OH, my paws and whiskers!'

>>> s.ljust(30)

'OH, my paws and whiskers!·····'

>>> s.rjust(30)

'·····OH, my paws and whiskers!'

Тип строки

>>> s.isalnum()

False

>>> s.isalpha()

False

>>> s.isprintable()

True

>>> s.istitle()

False

>>> s.isupper()

False

>>> s.isdecimal()

False

>>> s.isnumeric()

False

Атрибуты модуля string