Книга: Простой Python. Современный стиль программирования. 2-е изд.
Назад: Приложение В. Нечто совершенно иное: async
Дальше: Приложение Д. Вспомогательные таблицы

Приложение Г. Ответы к упражнениям

1. Python: с чем его едят

1.1. Если вы еще не установили Python 3, сделайте это сейчас. Прочтите приложение Б, чтобы узнать детали.

1.2. Запустите интерактивный интерпретатор Python 3. Детали опять же вы найдете в приложении Б. Интерпретатор должен вывести несколько строк о себе, а затем строку, начинающуюся с символов >>>. Перед вами приглашение для ввода команд Python.

Вот так это выглядит на моем Mac:

$ python

Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 16:39:00)

[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin

Type "help", "copyright", "credits" or "license" for more information.

>>>

1.3. Немного поэкспериментируйте с интерпретатором. Используйте его как калькулятор и наберите 8*9. Нажмите клавишу Enter, чтобы увидеть результат. Python должен вывести 72.

>>> 8 * 9

72

1.4. Теперь введите число 47 и нажмите клавишу Enter. Появилось ли число 47 в следующей строке?

>>> 47

47

1.5. Теперь введите print(47) и нажмите клавишу Enter. Появилось ли снова число 47 в следующей строке?

>>> print(47)

47

2. Типы данных, значения, переменные и имена

2.1. Присвойте целочисленное значение 99 переменной prince и выведите ее на экран.

>>> prince = 99

>>> print(prince)

99

>>>

2.2. Какого типа значение 5?

>>> type(5)

<class 'int'>

2.3. Какого типа значение 2.0?

>>> type(2.0)

<class 'float'>

2.4. Какого типа выражение 5+2.0?

>>> type(5 + 2.0)

<class 'float'>

3. Числа

3.1. Сколько секунд в часе? Используйте интерактивный интерпретатор как калькулятор и умножьте количество секунд в минуте (60) на количество минут в часе (тоже 60).

>>> 60 * 60

3600

3.2. Присвойте результат вычисления предыдущего задания (секунды в часе) переменной, которая называется seconds_per_hour.

>>> seconds_per_hour = 60 * 60

>>> seconds_per_hour

3600

3.3. Сколько секунд в сутках? Используйте переменную seconds_per_hour.

>>> seconds_per_hour * 24

86400

3.4. Снова посчитайте количество секунд в сутках, но на этот раз сохраните результат в переменной seconds_per_day.

>>> seconds_per_day = seconds_per_hour * 24

>>> seconds_per_day

86400

3.5. Разделите значение переменной seconds_per_day на значение переменной seconds_per_hour, используя деление с плавающей точкой (/).

>>> seconds_per_day / seconds_per_hour

24.0

3.6. Разделите значение переменной seconds_per_day на значение переменной seconds_per_hour, используя целочисленное деление (//). Совпадает ли полученный результат с ответом из предыдущего пункта без учета символов .0 в конце?

>>> seconds_per_day // seconds_per_hour

24

4. Выбираем с помощью if

4.1. Выберите число от 1 до 10 и присвойте его переменной secret. Выберите еще одно число от 1 до 10 и присвойте его переменной guess. Далее напишите условные проверки (if, else и elif), чтобы вывести строку 'toolow', если значение переменной guess меньше 7, 'toohigh', если оно больше 7, и 'justright', если равно secret.

Выбрали ли вы для переменной secret значение 7? Готов поспорить, так сделали многие, поскольку в числе 7 есть нечто волшебное.

secret = 7

guess = 5

if guess < secret:

    print('too low')

elif guess > secret:

    print('too high')

else:

    print('just right')

Запустите эту программу, и вы увидите следующее:

too low

4.2. Присвойте значения True или False переменным small и green. Напишите несколько утверждений if/else, которые выведут на экран информацию о том, соответствуют ли заданным условиям следующие растения: вишня, горошек, арбуз, тыква.

>>> small = False

>>> green = True

>>> if small:

...     if green:

...         print("pea")

...     else:

...         print("cherry")

... else:

...     if green:

...         print("watermelon")

...     else:

...         print("pumpkin")

...

Watermelon

5. Текстовые строки

5.1. Напишите с заглавной буквы слово, которое начинается с буквы m:

>>> song = """When an eel grabs your arm,

... And it causes great harm,

... That's - a moray!"""

Не забудьте о пробеле, стоящем перед буквой m:

>>> song = """When an eel grabs your arm,

... And it causes great harm,

... That's - a moray!"""

>>> song = song.replace(" m", " M")

>>> print(song)

When an eel grabs your arm,

And it causes great harm,

That's - a Moray!

5.2. Выведите на экран все вопросы из списка, а также правильные ответы в таком виде:

Q: вопрос

A: ответ

>>> questions = [

...     "We don't serve strings around here. Are you a string?",

...     "What is said on Father's Day in the forest?",

...     "What makes the sound 'Sis! Boom! Bah!'?"

...     ]

>>> answers = [

...     "An exploding sheep.",

...     "No, I'm a frayed knot.",

...     "'Pop!' goes the weasel."

...     ]

Вы могли бы вывести на экран все вопросы и ответы множеством способов. Попробуем использовать «бутерброд из кортежей» (конструкция, в которой в кортежах хранятся кортежи) с целью их сгруппировать, а затем распакуем кортежи, чтобы получить значения для вывода на экран:

questions = [

    "We don't serve strings around here. Are you a string?",

    "What is said on Father's Day in the forest?",

    "What makes the sound 'Sis! Boom! Bah!'?"

    ]

answers = [

    "An exploding sheep.",

    "No, I'm a frayed knot.",

    "'Pop!' goes the weasel."

    ]

 

q_a = ( (0, 1), (1,2), (2, 0) )

for q, a in q_a:

    print("Q:", questions[q])

    print("A:", answers[a])

    print()

Результат:

$ python qanda.py

Q: We don't serve strings around here. Are you a string?

A: No, I'm a frayed knot.

 

Q: What is said on Father's Day in the forest?

A: 'Pop!' goes the weasel.

 

Q: What makes the sound 'Sis! Boom! Bah!'?

A: An exploding sheep.

5.3. Выведите на экран следующее стихотворение, используя старый стиль форматирования. Подставьте в него такие строки: 'roastbeef', 'ham', 'head', и 'clam':

My kitty cat likes %s,

My kitty cat likes %s,

My kitty cat fell on his %s

And now thinks he's a %s.

>>> poem = '''

... My kitty cat likes %s,

... My kitty cat likes %s,

... My kitty cat fell on his %s

... And now thinks he's a %s.

... '''

>>> args = ('roast beef', 'ham', 'head', 'clam')

>>> print(poem % args)

 

My kitty cat likes roast beef,

My kitty cat likes ham,

My kitty cat fell on his head

And now thinks he's a clam.

5.4. Напишите письмо с использованием нового стиля форматирования. Сохраните предложенную строку в переменной letter (она понадобится вам в упражнении ниже):

Dear {salutation} {name},

 

Thank you for your letter. We are sorry that our {product}

{verbed} in your {room}. Please note that it should never

be used in a {room}, especially near any {animals}.

 

Send us your receipt and {amount} for shipping and handling.

We will send you another {product} that, in our tests,

is {percent}% less likely to have {verbed}.

 

Thank you for your support.

 

Sincerely,

{spokesman}

{job_title}

>>> letter = '''

... Dear {salutation} {name},

...

... Thank you for your letter. We are sorry that our {product}

... {verbed} in your {room}. Please note that it should never

... be used in a {room}, especially near any {animals}.

...

... Send us your receipt and {amount} for shipping and handling.

... We will send you another {product} that, in our tests,

... is {percent}% less likely to have {verbed}.

...

... Thank you for your support.

...

... Sincerely,

... {spokesman}

... {job_title}

... '''

5.5. Присвойте значения переменным 'salutation', 'name', 'product', 'verbed' (глагол в прошедшем времени), 'room', 'animals', 'percent', 'spokesman' и 'job_title'. С помощью функции letter.format() выведите на экран значение переменной letter, в которую подставлены эти значения.

>>> print (

...     letter.format(salutation='Ambassador',

...                   name='Nibbler',

...                   product='pudding',

...                   verbed='evaporated',

...                   room='gazebo',

...                   animals='octothorpes',

...                   amount='$1.99',

...                   percent=88,

...                   spokesman='Shirley Iugeste',

...                   job_title='I Hate This Job')

...     )

 

Dear Ambassador Nibbler,

 

Thank you for your letter. We are sorry that our pudding

evaporated in your gazebo. Please note that it should never

be used in a gazebo, especially near any octothorpes.

 

Send us your receipt and $1.99 for shipping and handling.

We will send you another pudding that, in our tests,

is 88% less likely to have evaporated.

 

Thank you for your support.

 

Sincerely,

Shirley Iugeste

I Hate This Job

5.6. После проведения публичных опросов с целью выбора имени появились: английская подводная лодка Boaty McBoatface, австралийская беговая лошадь Horsey McHorseface и шведский поезд Trainy McTrainface. Используйте форматирование с символом % для того, чтобы вывести на экран победившие имена для утки, тыквы и шпица (пример Д.1).

Пример Д.1. mcnames1.py

names = ["duck", "gourd", "spitz"]

for name in names:

    cap_name = name.capitalize()

    print("%sy Mc%sface" % (cap_name, cap_name))

 

Output:

 

    Ducky McDuckface

    Gourdy McGourdface

    Spitzy McSpitzface

5.7. Сделайте то же самое с помощью функции format() (пример Д.2).

Пример Д.2. mcnames2.py

names = ["duck", "gourd", "spitz"]

for name in names:

   cap_name = name.capitalize()

    print("{}y Mc{}face".format(cap_name, cap_name))

5.8. А теперь еще раз с использованием f-строк (пример Д.3).

Пример Д.3. mcnames3.py

names = ["duck", "gourd", "spitz"]

for name in names:

    cap_name = name.capitalize()

    print(f"{cap_name}y Mc{cap_name}face")

6. Создаем циклы с помощью ключевых слов while и for

6.1. Используйте цикл for, чтобы вывести на экран значения списка [3,2,1,0].

>>> for value in [3, 2, 1, 0]:

...  print(value)

...

3

2

1

0

6.2. Присвойте значение 7 переменной guess_me и значение 1 переменной number. Напишите цикл while, который сравнивает переменные number и guess_me. Выведите строку 'toolow', если значение переменной number меньше значения переменной guess_me. Если значение переменной number равно значению переменной guess_me, выведите строку 'foundit!' и выйдите из цикла. Если значение переменной number больше значения переменной guess_me, выведите строку 'oops' и выйдите из цикла. Увеличьте значение переменной number на выходе из цикла.

guess_me = 7

number = 1

while True:

    if number < guess_me:

        print('too low')

    elif number == guess_me:

        print('found it!')

       break

    elif number > guess_me:

        print('oops')

        break

    number += 1

Если вы сделали все правильно, то увидите следующие строки.

too low

too low

too low

too low

too low

too low

found it!

Обратите внимание: строка elif number > guess_me: могла содержать обычный оператор else: в связи с тем, что если значение number не меньше и не равно значению guess_me, то оно должно быть больше. По крайней мере в этой Вселенной.

6.3. Присвойте значение 5 переменной guess_me. Используйте цикл for, чтобы проитерировать с помощью переменной number по диапазону range(10). Если значение переменной number меньше, чем значение guess_me, выведите на экран сообщение 'toolow'. Если оно равно значению guess_me — выведите сообщение foundit!, а затем выйдите из цикла. Если значение переменной number больше, чем guess_me, выведите на экран сообщение 'oops' и выйдите из цикла.

>>> guess_me = 5

>>> for number in range(10):

...     if number < guess_me:

...         print("too low")

...     elif number == guess_me:

...         print("found it!")

...         break

...     else:

...         print("oops")

...         break

...

too low

too low

too low

too low

too low

found it!

7. Кортежи и списки

7.1. Создайте список years_list, содержащий год, в который вы родились, и каждый последующий год вплоть до вашего пятого дня рождения. Например, если вы родились в 1980 году, то список будет выглядеть так: years_list=[1980,1981,1982,1983,1984,1985].

Если вы родились в 1980-м, то вам нужно ввести следующее:

>>> years_list = [1980, 1981, 1982, 1983, 1984, 1985]

7.2. В какой год из списка years_list был ваш третий день рождения? Учтите, в первый год вам было 0 лет.

Вам нужно смещение 3. Поэтому, если вы родились в 1980-м:

>>> years_list[3]

1983

7.3. В какой год из списка years_list вам было больше всего лет?

Вам нужно получить последний год, поэтому используйте смещение -1. Вы также можете использовать смещение 5, поскольку знаете, что в этом списке всего шесть элементов. Однако смещение -1 позволяет получить последний элемент из списка любой длины. Для тех, кто родился в 1980 году:

>>> years_list[-1]

1985

7.4. Создайте список things, содержащий три элемента: "mozzarella", "cinderella", "salmonella".

>>> things = ["mozzarella", "cinderella", "salmonella"]

>>> things

['mozzarella', 'cinderella', 'salmonella']

7.5. Напишите с большой буквы тот элемент списка things, который означает человека, а затем выведите список. Изменился ли элемент списка?

Эта строка записывает слово с прописной буквы, но не меняет его в списке:

>>> things[1].capitalize()

'Cinderella'

>>> things

['mozzarella', 'cinderella', 'salmonella']

Если вы хотите изменить его в списке, вам нужно присвоить его снова:

>>> things[1] = things[1].capitalize()

>>> things

['mozzarella', 'Cinderella', 'salmonella']

7.6. Переведите сырный элемент списка things в верхний регистр целиком и выведите список.

>>> things[0] = things[0].upper()

>>> things

['MOZZARELLA', 'Cinderella', 'salmonella']

7.7. Удалите из списка things заболевание, получите Нобелевскую премию и затем выведите список на экран.

Это удалит элемент по значению:

>>> things.remove("salmonella")

>>> things

['MOZZARELLA', 'Cinderella']

Поскольку элемент находится на последнем месте в списке, следующая строка тоже сработает:

>>> del things[-1]

Элемент также можно удалить, указав смещение от начала:

>>> del things[2]

7.8. Создайте список с элементами "Groucho", "Chico" и "Harpo"; назовите его surprise.

>>> surprise = ['Groucho', 'Chico', 'Harpo']

>>> surprise

['Groucho', 'Chico', 'Harpo']

7.9. Напишите последний элемент списка surprise со строчной буквы, затем выведите эту строку в обратном порядке и с прописной буквы.

>>> surprise[-1] = surprise[-1].lower()

>>> surprise[-1] = surprise[-1][::-1]

>>> surprise[-1].capitalize()

'Oprah'

7.10. Используйте списковое включение, чтобы создать список с именем even, в котором будут содержаться четные числа в промежутке range(10).

>>> even = [number for number in range(10) if number % 2 == 0]

>>> even

[0, 2, 4, 6, 8]

7.11. Попробуйте создать генератор рифм для прыжков через скакалку. Нужно вывести на экран последовательность двухстрочных рифм. Начните программу с этого фрагмента:

start1 = ["fee", "fie", "foe"]

rhymes = [

    ("flop", "get a mop"),

    ("fope", "turn the rope"),

    ("fa", "get your ma"),

    ("fudge", "call the judge"),

    ("fat", "pet the cat"),

    ("fog", "walk the dog"),

    ("fun", "say we're done"),

    ]

start2 = "Someone better"

Затем следуйте инструкциям.

Для каждого кортежа (first,second) в списке rhymes:

для первой строки:

• выведите на экран каждую строку списка start1, записав их с большой буквы, за которыми следует восклицательный знак и пробел;

• выведите на экран значение переменной first, также записав его с большой буквы, за которым следует восклицательный знак;

• для второй строки:

• выведите на экран значение переменной start2 и пробел;

• выведите на экран значение переменной second и точку.

start1 = ["fee", "fie", "foe"]

rhymes = [

    ("flop", "get a mop"),

    ("fope", "turn the rope"),

    ("fa", "get your ma"),

    ("fudge", "call the judge"),

    ("fat", "pet the cat"),

    ("fog", "pet the dog"),

    ("fun", "say we're done"),

    ]

start2 = "Someone better"

start1_caps = " ".join([word.capitalize() + "!" for word in start1])

for first, second in rhymes:

    print(f"{start1_caps} {first.capitalize()}!")

    print(f"{start2} {second}.")

Результат:

Fee! Fie! Foe! Flop!

Someone better get a mop.

Fee! Fie! Foe! Fope!

Someone better turn the rope.

Fee! Fie! Foe! Fa!

Someone better get your ma.

Fee! Fie! Foe! Fudge!

Someone better call the judge.

Fee! Fie! Foe! Fat!

Someone better pet the cat.

Fee! Fie! Foe! Fog!

Someone better walk the dog.

Fee! Fie! Foe! Fun!

Someone better say we're done.

8. Словари и множества

8.1. Создайте англо-французский словарь с названием e2f и выведите его на экран. Вот ваши первые слова: dog/chien, cat/chat и walrus/morse.

>>> e2f = {'dog': 'chien', 'cat': 'chat', 'walrus': 'morse'}

>>> e2f

{'cat': 'chat', 'walrus': 'morse', 'dog': 'chien'}

8.2. Используя словарь e2f, выведите французский вариант слова walrus.

>>> e2f['walrus']

'morse'

8.3. Создайте французско-английский словарь f2e на основе словаря e2f. Используйте метод items.

>>> f2e = {}

>>> for english, french in e2f.items():

    f2e[french] = english

>>> f2e

{'morse': 'walrus', 'chien': 'dog', 'chat': 'cat'}

8.4. Используя словарь f2e, выведите английский вариант слова chien.

>>> f2e['chien']

'dog'

8.5. Выведите на экран множество английских слов из ключей словаря e2f.

>>> set(e2f.keys())

{'cat', 'walrus', 'dog'}

8.6. Создайте многоуровневый словарь life. Используйте следующие строки для ключей верхнего уровня: 'animals', 'plants' и 'other'. Сделайте так, чтобы ключ 'animals' ссылался на другой словарь, имеющий ключи 'cats', 'octopi' и 'emus'. Сделайте так, чтобы ключ 'cats' ссылался на список строк со значениями 'Henri', 'Grumpy' и 'Lucy'. Остальные ключи должны ссылаться на пустые словари.

Это довольно трудный пример, так что если вы заглянули сюда, то ничего особо страшного не случилось:

>>> life = {

...     'animals': {

...         'cats': [

...             'Henri', 'Grumpy', 'Lucy'

...             ],

...         'octopi': {},

...         'emus': {}

...         },

...     'plants': {},

...     'other': {}

...     }

>>>

8.7. Выведите на экран высокоуровневые ключи словаря life.

>>> print(life.keys())

dict_keys(['animals', 'other', 'plants'])

Python 3 содержит функционал для работы с ключами словарей. Чтобы вывести их как список, используйте следующую строку:

>>> print(list(life.keys()))

['animals', 'other', 'plants']

Вы можете использовать пробелы, чтобы сделать ваш код более читабельным:

>>> print ( list ( life.keys() ) )

['animals', 'other', 'plants']

8.8. Выведите на экран ключи life['animals'].

>>> print(life['animals'].keys())

dict_keys(['cats', 'octopi', 'emus'])

8.9. Выведите значения life['animals']['cats'].

>>> print(life['animals']['cats'])

['Henri', 'Grumpy', 'Lucy']

8.10. Используйте генератор словаря, чтобы создать словарь squares. Используйте range(10), чтобы получить ключи. В качестве значений используйте возведенное в квадрат значение каждого ключа.

>>> squares = {key: key*key for key in range(10)}

>>> squares

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

8.11. Используйте генератор множества, чтобы создать множество odd из нечетных чисел диапазона range(10).

>>> odd = {number for number in range(10) if number % 2 == 1}

>>> odd

{1, 3, 5, 7, 9}

8.12. Используйте включение генератора, чтобы вернуть строку 'Got' и числа из диапазона range(10). Итерируйте по этой конструкции с помощью цикла for.

>>> for thing in ('Got %s' % number for number in range(10)):

...    print(thing)

...

Got 0

Got 1

Got 2

Got 3

Got 4

Got 5

Got 6

Got 7

Got 8

Got 9

8.13. Используйте функцию zip(), чтобы создать словарь из кортежа ключей ('optimist', 'pessimist', 'troll') и кортежа значений ('Theglassishalffull', 'Theglassishalfempty', 'Howdidyougetaglass?’).

>>> keys = ('optimist', 'pessimist', 'troll')

>>> values = ('The glass is half full',

...     'The glass is half empty',

...     'How did you get a glass?')

>>> dict(zip(keys, values))

{'optimist': 'The glass is half full',

'pessimist': 'The glass is half empty',

'troll': 'How did you get a glass?'}

8.14. Используйте функцию zip(), чтобы создать словарь с именем movies, в котором объединены списки titles=['CreatureofHabit','CrewelFate','SharksOnaPlane'] и plots=['Anunturnsintoamonster','Ahauntedyarnshop','Checkyourexits'].

>>> titles = ['Creature of Habit',

...     'Crewel Fate',

...     'Sharks On a Plane']

>>> plots = ['A nun turns into a monster',

...     'A haunted yarn shop',

...     'Check your exits']

>>> movies = dict(zip(titles, plots))

>>> movies

{'Creature of Habit': 'A nun turns into a monster',

'Crewel Fate': 'A haunted yarn shop',

'Sharks On a Plane': 'Check your exits'}

>>>

9. Функции

9.1. Определите функцию good, которая возвращает следующий список: ['Harry', 'Ron', 'Hermione'].

>>> def good():

...     return ['Harry', 'Ron', 'Hermione']

...

>>> good()

['Harry', 'Ron', 'Hermione']

9.2. Определите функцию генератора get_odds, которая возвращает нечетные числа из диапазона range(10). Используйте цикл for, чтобы найти и вывести третье возвращенное значение.

>>> def get_odds():

...     for number in range(1, 10, 2):

...         yield number

...

>>> count = 1

>>> for number in get_odds():

...     if count == 3:

...         print("The third odd number is", number)

...         break

...     count += 1

...

Третье нечетное число равно 5.

9.3. Определите декоратор test, который выводит строку 'start' при вызове функции и строку 'end', когда функция завершает свою работу.

>>> def test(func):

...     def new_func(*args, **kwargs):

...         print('start')

...         result = func(*args, **kwargs)

...         print('end')

...         return result

...     return new_func

...

>>>

>>> @test

... def greeting():

...     print("Greetings, Earthling")

...

>>> greeting()

start

Greetings, Earthling

end

  9.4. Определите исключение OopsException. Сгенерируйте его и посмотрите, что произойдет. Затем напишите код, позволяющий поймать это исключение и вывести строку 'Caughtanoops'.

>>> class OopsException(Exception):

...     pass

...

>>> raise OopsException()

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

__main__.OopsException

>>>

>>> try:

...     raise OopsException

... except OopsException:

...     print('Caught an oops')

...

Caught an oops

10. Ой-ой-ой: объекты и классы

10.1. Создайте класс Thing, не имеющий содержимого, и выведите его на экран. Затем создайте объект example этого класса и также выведите его. Совпадают ли выведенные значения?

>>> class Thing:

...     pass

...

>>> print(Thing)

<class '__main__.Thing'>

>>> example = Thing()

>>> print(example)

<__main__.Thing object at 0x1006f3fd0>

10.2. Создайте новый класс с именем Thing2 и присвойте переменной letters значение 'abc'. Выведите на экран значение letters.

>>> class Thing2:

...     letters = 'abc'

...

>>> print(Thing2.letters)

abc

10.3. Создайте еще один класс, который, конечно же, называется Thing3. В этот раз присвойте значение 'xyz' переменной объекта letters. Выведите на экран значение атрибута letters. Понадобилось ли вам создавать объект класса, чтобы сделать это?

>>> class Thing3:

...     def __init__(self):

...         self.letters = 'xyz'

...

Переменная letters принадлежит любому объекту класса Thing3, но не самому классу Thing3:

>>> print(Thing3.letters)

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

AttributeError: type object 'Thing3' has no attribute 'letters'

>>> something = Thing3()

>>> print(something.letters)

xyz

10.4. Создайте класс Element, имеющий атрибуты объекта name, symbol и number. Создайте объект этого класса со значениями 'Hydrogen', 'H' и 1.

>>> class Element:

...     def __init__(self, name, symbol, number):

...         self.name = name

...         self.symbol = symbol

...         self.number = number

...

>>> hydrogen = Element('Hydrogen', 'H', 1)

10.5. Создайте словарь со следующими ключами и значениями: 'name': 'Hydrogen', 'symbol': 'H', 'number': 1. Далее создайте объект с именем hydrogen класса Element с помощью этого словаря.

Начнем со словаря:

>>> el_dict = {'name': 'Hydrogen', 'symbol': 'H', 'number': 1}

Это работает, однако необходимо напечатать много текста:

>>> hydrogen = Element(el_dict['name'], el_dict['symbol'], el_dict['number'])

Убедимся, что это работает:

>>> hydrogen.name

'Hydrogen'

Однако вы также можете инициализировать объект непосредственно с помощью словаря, поскольку его ключ имени совпадает с аргументами функции __init__ (аргументы — ключевые слова рассматриваются в главе 9):

>>> hydrogen = Element(**el_dict)

>>> hydrogen.name

'Hydrogen'

10.6. Для класса Element определите метод с именем dump(), который выводит на экран значения атрибутов объекта (name, symbol и number). Создайте объект hydrogen из этого нового определения и используйте метод dump(), чтобы вывести на экран его атрибуты.

>>> class Element:

...     def __init__(self, name, symbol, number):

...         self.name = name

...         self.symbol = symbol

...         self.number = number

...     def dump(self):

...         print('name=%s, symbol=%s, number=%s' %

...             (self.name, self.symbol, self.number))

...

>>> hydrogen = Element(**el_dict)

>>> hydrogen.dump()

name=Hydrogen, symbol=H, number=1

10.7. Вызовите функцию print(hydrogen). В определении класса Element измените имя метода dump на __str__, создайте новый объект hydrogen и затем снова вызовите метод print(hydrogen).

>>> print(hydrogen)

<__main__.Element object at 0x1006f5310>

>>> class Element:

...     def __init__(self, name, symbol, number):

...         self.name = name

...         self.symbol = symbol

...         self.number = number

...     def __str__(self):

...         return ('name=%s, symbol=%s, number=%s' %

...             (self.name, self.symbol, self.number))

...

>>> hydrogen = Element(**el_dict)

>>> print(hydrogen)

name=Hydrogen, symbol=H, number=1

Метод __str__() — это один из волшебных методов Python. Функция print вызывает метод объекта __str__(), чтобы получить его строковое представление. Если у объекта нет метода __str__(), то он получает метод по умолчанию от его родительского класса Object, который возвращает строку наподобие <__main__.Element object at 0x1006f5310>.

10.8. Модифицируйте класс Element, сделав атрибуты name, symbol и number приватными. Определите свойство получателя для каждого атрибута, возвращающее его значение.

>>> class Element:

...     def __init__(self, name, symbol, number):

...         self.__name = name

...         self.__symbol = symbol

...         self.__number = number

...     @property

...     def name(self):

...         return self.__name

...     @property

...     def symbol(self):

...         return self.__symbol

...     @property

...     def number(self):

...         return self.__number

...

>>> hydrogen = Element('Hydrogen', 'H', 1)

>>> hydrogen.name

'Hydrogen'

>>> hydrogen.symbol

'H'

>>> hydrogen.number

1

10.9. Определите три класса: Bear, Rabbit и Octothorpe. Для каждого из них определите всего один метод — eats(). Этот метод должен возвращать значения 'berries' (для Bear), 'clover' (для Rabbit) или 'campers' (для Octothorpe). Создайте по одному объекту каждого класса и выведите на экран то, что ест указанное животное.

>> class Bear:

...     def eats(self):

...         return 'berries'

...

>>> class Rabbit:

...     def eats(self):

...         return 'clover'

...

>>> class Octothorpe:

...     def eats(self):

...         return 'campers'

...

>>> b = Bear()

>>> r = Rabbit()

>>> o = Octothorpe()

>>> print(b.eats())

berries

>>> print(r.eats())

clover

>>> print(o.eats())

campers

10.10. Определите три класса: Laser, Claw и SmartPhone. Каждый из них имеет только один метод — does(). Он возвращает значения 'disintegrate' (для Laser), 'crush' (для Claw) или 'ring' (для SmartPhone). Далее определите класс Robot, содержащий по одному объекту каждого из этих классов. Определите метод does() для класса Robot, который выводит на экран все, что делают его компоненты.

>>> class Laser:

...     def does(self):

...         return 'disintegrate'

...

>>> class Claw:

...     def does(self):

...         return 'crush'

...

>>> class SmartPhone:

...     def does(self):

...         return 'ring'

...

>>> class Robot:

...     def __init__(self):

...         self.laser = Laser()

...         self.claw = Claw()

...         self.smartphone = SmartPhone()

...     def does(self):

...         return '''I have many attachments:

... My laser, to %s.

... My claw, to %s.

... My smartphone, to %s.''' % (

...     self.laser.does(),

...     self.claw.does(),

...     self.smartphone.does() )

...

>>> robbie = Robot()

>>> print( robbie.does() )

I have many attachments:

My laser, to disintegrate.

My claw, to crush.

My smartphone, to ring.

11. Модули, пакеты и программы

11.1. Создайте файл с именем zoo.py. В нем объявите функцию hours(), которая выводит на экран строку 'Open9-5daily'. Далее используйте интерактивный интерпретатор, чтобы импортировать модуль zoo и вызвать его функцию hours().

Так выглядит файл zoo.py:

def hours():

    print('Open 9-5 daily')

А теперь импортируем его интерактивно:

>>> import zoo

>>> zoo.hours()

Open 9-5 daily

11.2. В интерактивном интерпретаторе импортируйте модуль zoo под именем menagerie и вызовите его функцию hours().

>>> import zoo as menagerie

>>> menagerie.hours()

Open 9-5 daily

11.3. Оставаясь в интерпретаторе, импортируйте непосредственно функцию hours() из модуля zoo и вызовите ее.

>>> from zoo import hours

>>> hours()

Open 9-5 daily

11.4. Импортируйте функцию hours() под именем info и вызовите ее.

>>> from zoo import hours as info

>>> info()

Open 9-5 daily

11.5. Создайте словарь с именем plain, содержащий пары «ключ — значение» 'a':1,'b':2 и 'c':3, а затем выведите его на экран.

>>> plain = {'a': 1, 'b': 2, 'c': 3}

>>> plain

{'a': 1, 'c': 3, 'b': 2}

11.6. Создайте OrderedDict с именем fancy из пар «ключ — значение», приведенных в упражнении 11.5, и выведите его на экран. Изменился ли порядок ключей?

>>> from collections import OrderedDict

>>> fancy = OrderedDict([('a', 1), ('b', 2), ('c', 3)])

>>> fancy

OrderedDict([('a', 1), ('b', 2), ('c', 3)])

11.7. Создайте defaultdict с именем dict_of_lists и передайте ему аргумент list. Создайте список dict_of_lists['a'] и присоедините к нему значение 'somethingfora' за одну операцию. Выведите на экран dict_of_lists['a'].

>>> from collections import defaultdict

>>> dict_of_lists = defaultdict(list)

>>> dict_of_lists['a'].append('something for a')

>>> dict_of_lists['a']

['something for a']

12. Обрабатываем данные

12.1. Создайте строку Unicode с именем mystery и присвойте ей значение '\U0001f4a9'. Выведите на экран значение mystery и ее имя Unicode.

>>> import unicodedata

>>> mystery = '\U0001f984'

>>> mystery

'159704.png'

>>> unicodedata.name(mystery)

'PILE OF POO'

Ой-ой-ой! Что еще у них там есть?

12.2. Закодируйте строку mystery, на этот раз с использованием кодировки UTF-8, в переменную типа bytes с именем pop_bytes. Выведите на экран значение переменной pop_bytes.

>>> pop_bytes = mystery.encode('utf-8')

>>> pop_bytes

b'\xf0\x9f\x92\xa9'

12.3. Используя кодировку UTF-8, декодируйте переменную popbytes в строку pop_string. Выведите на экран значение переменной pop_string. Равно ли оно значению переменной mystery?

>>> pop_string = pop_bytes.decode('utf-8')

>>> pop_string

'159706.png'

>>> pop_string == mystery

True

12.4. При работе с текстом вам могут пригодиться регулярные выражения. Мы воспользуемся ими несколькими способами в следующем примере текста. Перед вами стихотворение Ode on the Mammoth Cheese, написанное Джеймсом Макинтайром в 1866 году во славу головки сыра весом 7000 фунтов, которая была изготовлена в Онтарио и отправлена в международное путешествие. Если не хотите самостоятельно перепечатывать это стихотворение, используйте свой любимый поисковик и скопируйте текст в программу. Или скопируйте стихотворение из проекта «Гутенберг» (). Назовите следующую строку mammoth.

>>> mammoth = '''

... We have seen thee, queen of cheese,

... Lying quietly at your ease,

... Gently fanned by evening breeze,

... Thy fair form no flies dare seize.

...

... All gaily dressed soon you'll go

... To the great Provincial show,

... To be admired by many a beau

... In the city of Toronto.

...

... Cows numerous as a swarm of bees,

... Or as the leaves upon the trees,

... It did require to make thee please,

... And stand unrivalled, queen of cheese.

...

... May you not receive a scar as

... We have heard that Mr. Harris

... Intends to send you off as far as

... The great world's show at Paris.

...

... Of the youth beware of these,

... For some of them might rudely squeeze

... And bite your cheek, then songs or glees

... We could not sing, oh! queen of cheese.

...

... We'rt thou suspended from balloon,

... You'd cast a shade even at noon,

... Folks would think it was the moon

... About to fall and crush them soon.

... '''

12.5. Импортируйте модуль re, чтобы использовать функции регулярных выражений в Python. Примените функцию re.findall() для вывода на экран всех слов, которые начинаются с буквы с.

Мы определим переменную pat для шаблона и затем будем искать такой шаблон в строке mammoth:

>>> import re

>>> pat = r'\bc\w*'

>>> re.findall(pat, mammoth)

['cheese', 'city', 'cheese', 'cheek', 'could', 'cheese', 'cast', 'crush']

Элемент \b означает, что нужно начать с границы между словом и не словом. Используйте такую конструкцию, чтобы указать либо на начало, либо на конец слова. Литерал c — это первая буква всех слов, которые мы ищем. Элемент \w означает любой символ слова, которое включает в себя буквы, цифры и подчеркивания (_). Элемент * означает ноль или больше таких символов. Целиком это выражение находит слова, которые начинаются с с, включая 'c'. Если вы не использовали простую строку (у таких строк r стоит прямо перед открывающей кавычкой), Python интерпретирует \b как возврат на шаг, и поиск по таинственной причине ничего не найдет:

>>> pat = '\bc\w*'

>>> re.findall(pat, mammoth)

[]

12.6. Найдите все четырехбуквенные слова, которые начинаются с буквы c.

>>> pat = r'\bc\w{3}\b'

>>> re.findall(pat, mammoth)

['city', 'cast']

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

>>> pat = r'\bc\w{3}'

>>> re.findall(pat, mammoth)

['chee', 'city', 'chee', 'chee', 'coul', 'chee', 'cast', 'crus']

12.7. Найдите все слова, которые заканчиваются на букву r.

Это упражнение с подвохом. Мы получаем правильный результат для слов, которые заканчиваются на r:

>>> pat = r'\b\w*r\b'

>>> re.findall(pat,mammoth)

['your', 'fair', 'Or', 'scar', 'Mr', 'far', 'For', 'your', 'or']

Однако результаты будут не так хороши, если мы поищем слова, которые заканчиваются на l:

>>> pat = r'\b\w*l\b'

>>> re.findall(pat,mammoth)

['All', 'll', 'Provincial', 'fall']

Что здесь делает буквосочетание ll? Паттерн \w совпадает только c буквами, цифрами и подчеркиваниями, но не с апострофами ASCII. В результате вы увидите буквосочетание ll. Мы можем обработать этот крайний случай, добавив апостроф в список символов, с которыми должен совпасть набор символов. Наша первая попытка не работает:

>>> pat = r'\b[\w']*l\b'

  File "<stdin>", line 1

    pat = r'\b[\w']*l\b'

Python указывает на окрестности ошибки, но может потребоваться какое-то время на осознание: ошибка заключалась в том, что строка шаблона окружена такими же апострофами — символами кавычки. Один из способов решить эту проблему — использовать управляющую последовательность с обратным слешем:

>>> pat = r'\b[\w\']*l\b'

>>> re.findall(pat, mammoth)

['All', "you'll", 'Provincial', 'fall']

Еще одно решение — окружить строку шаблона двойными кавычками:

>>> pat = r"\b[\w']*l\b"

>>> re.findall(pat, mammoth)

['All', "you'll", 'Provincial', 'fall']

Это упражнение с подвохом. Мы получаем правильный результат для слов, которые заканчиваются на r:

>>> pat = r'\b\w*r\b'

>>> re.findall(pat,mammoth)

['your', 'fair', 'Or', 'scar', 'Mr', 'far', 'For', 'your', 'or']

Однако результаты будут не так хороши, если мы поищем слова, которые заканчиваются на l:

>>> pat = r'\b\w*l\b'

>>> re.findall(pat,mammoth)

['All', 'll', 'Provincial', 'fall']

Что здесь делает буквосочетание ll? Паттерн \w совпадает только c буквами, цифрами и подчеркиваниями, но не с апострофами ASCII. В результате вы увидите буквосочетание ll. Мы можем обработать этот крайний случай, добавив апостроф в список символов, с которыми должен совпасть набор символов. Наша первая попытка не работает:

>>> pat = r'\b[\w']*l\b'

  File "<stdin>", line 1

    pat = r'\b[\w']*l\b'

Python указывает на окрестности ошибки, но может потребоваться какое-то время на осознание: ошибка заключалась в том, что строка шаблона окружена такими же апострофами — символами кавычки. Один из способов решить эту проблему — использовать управляющую последовательность с обратным слешем:

>>> pat = r'\b[\w\']*l\b'

>>> re.findall(pat, mammoth)

['All', "you'll", 'Provincial', 'fall']

Еще одно решение — окружить строку шаблона двойными кавычками:

>>> pat = r"\b[\w']*l\b"

>>> re.findall(pat, mammoth)

['All', "you'll", 'Provincial', 'fall']

12.8. Найдите все слова, которые содержат три гласные подряд.

Начиная с границы слова, любое количество символов слова, три гласные и далее любые символы, не являющиеся гласными, до конца слова:

>>> pat = r'\b[^aeiou]*[aeiou]{3}[^aeiou]*\b'

>>> re.findall(pat, mammoth)

['queen', 'quietly', 'beau\nIn', 'queen', 'squeeze', 'queen']

Выглядит правильно, за исключением строки 'beau\nIn'. Мы искали строку mammoth целиком. Конструкция [^aeiou] совпадает с любыми символами, не являющимися гласными, включая \n (перенос строки, который отмечает конец текстовой строки). Нам нужно добавить еще кое-что в набор игнорируемых символов: \s совпадает с любыми символами пробелов, включая \n:

>>> pat = r'\b\w*[aeiou]{3}[^aeiou\s]\w*\b'

>>> re.findall(pat, mammoth)

['queen', 'quietly', 'queen', 'squeeze', 'queen']

На сей раз мы не нашли слово beau, поэтому нужно внести в шаблон еще одно исправление: совпадение с любым числом (даже нулем) не гласных после трех гласных. Наш предыдущий шаблон всегда совпадал с одним не гласным символом:

>>> pat = r'\b\w*[aeiou]{3}[^aeiou\s]*\w*\b'

>>> re.findall(pat, mammoth)

['queen', 'quietly', 'beau', 'queen', 'squeeze', 'queen']

Что это показывает? Среди всего прочего то, что регулярные выражения могут пригодиться для многого, но их может быть очень трудно написать правильно.

12.9. Используйте метод unhexlify для того, чтобы преобразовать эту шестнадцатеричную строку, созданную путем объединения двух строк для размещения на странице, в переменную типа bytes с именем gif.

'47494638396101000100800000000000ffffff21f9' +

'0401000000002c000000000100010000020144003b'

>>> import binascii

>>> hex_str = '47494638396101000100800000000000ffffff21f9' + \

...     '0401000000002c000000000100010000020144003b'

>>> gif = binascii.unhexlify(hex_str)

>>> len(gif)

42

12.10. Байты, содержащиеся в переменной gif, определяют однопиксельный прозрачный GIF-файл. Этот формат является одним из самых распространенных. Корректный файл формата GIF начинается со строки GIF89a. Корректен ли этот файл?

>>> gif[:6] == b'GIF89a'

True

Обратите внимание: с помощью b мы можем указать, что строка состоит из байтов, а не из символов Unicode. Вы можете сравнить байты с байтами, но не байты и символы:

>>> gif[:6] == 'GIF89a'

False

>>> type(gif)

<class 'bytes'>

>>> type('GIF89a')

<class 'str'>

>>> type(b'GIF89a')

<class 'bytes'>

12.11. Ширина GIF-файла в пикселах является шестнадцатибитным целым числом с обратным порядком байтов, которое начинается со смещения 6 байт. Высота имеет такой же размер и начинается со смещения 8 байт. Извлеките и выведите на экран эти значения для переменной gif. Равны ли они 1?

>>> import struct

>>> width, height = struct.unpack('<HH', gif[6:10])

>>> width, height

(1, 1)

13. Календари и часы

13.1. Запишите текущие дату и время как строку в текстовый файл today.txt.

>>> from datetime import date

>>> now = date.today()

>>> now_str = now.isoformat()

>>> with open('today.txt', 'wt') as output:

...    print(now_str, file=output)

>>>

Когда я запустил этот фрагмент кода, в файле today.txt увидел следующее:

2019-07-23

Вместо функции print вы могли бы задействовать такую строку, как output.write(now_str). Использование функции print добавляет символ перевода строки в конце.

13.2. Прочтите текстовый файл today.txt и разместите данные в строке today_string.

>>> with open('today.txt', 'rt') as input:

...     today_string = input.read()

...

>>> today_string

'2019-07-23\n'

13.3. Проанализируйте дату из строки today_string.

>>> fmt = '%Y-%m-%d\n'

>>> datetime.strptime(today_string, fmt)

datetime.datetime(2019, 7, 23, 0, 0)

Если вы записали тот символ новой строки в файл, то вам нужно, чтобы он совпал со строкой формата.

13.4. Создайте объект date с датой вашего рождения.

Предположим, вы родились 14 августа 1982 года:

>>> my_day = date(1982, 8, 14)

>>> my_day

datetime.date(1982, 8, 14)

13.5. В какой день недели вы родились?

>>> my_day.weekday()

5

>>> my_day.isoweekday()

6

Для weekday() значение для понедельника равно 0, а для воскресенья — 6. Для функции isoweekday() значение для понедельника равно 1, а для воскресенья — 7. Поэтому искомый день — суббота.

13.6. Когда вам будет (или уже было) 10 000 дней от роду?

>>> from datetime import timedelta

>>> party_day = my_day + timedelta(days=10000)

>>> party_day

datetime.date(2009, 12, 30)

Если это был ваш день рождения, то вы, возможно, пропустили еще один повод повеселиться.

14. Файлы и каталоги

14.1. Выведите на экран список файлов текущего каталога.

Если ваш текущий каталог называется ohmy и содержит три файла с именами по названиям животных, то код может выглядеть так:

>>> import os

>>> os.listdir('.')

['bears', 'lions', 'tigers']

14.2. Выведите на экран список всех файлов родительского каталога.

Если родительский каталог содержит два файла и текущий каталог ohmy, то код может выглядеть так:

>>> import os

>>> os.listdir('..')

['ohmy', 'paws', 'whiskers']

14.3. Присвойте строку Thisisatestoftheemergencytextsystem переменной test1 и запишите эту переменную в файл с именем test.txt.

>>> test1 = 'This is a test of the emergency text system'

>>> len(test1)

43

Вот как это можно сделать с помощью функций open, write и close:

>>> outfile = open('test.txt', 'wt')

>>> outfile.write(test1)

43

>>> outfile.close()

Или можете использовать with и избежать вызова close (Python сделает это за вас):

>>> with open('test.txt', 'wt') as outfile:

...  outfile.write(test1)

...

43

14.4. Откройте файл test.txt и считайте его содержимое в строку test2. Будут ли одинаковыми строки test1 и test2?

>>> with open('test.txt', 'rt') as infile:

...     test2 = infile.read()

...

>>> len(test2)

43

>>> test1 == test2

True

15. Данные во времени: процессы и конкурентность

15.1. Используйте модуль multiprocessing, чтобы создать три отдельных процесса. Заставьте каждый из них подождать случайное количество секунд между нулем и единицей, вывести текущее время, а затем завершить работу.

import multiprocessing

 

def now(seconds):

    from datetime import datetime

    from time import sleep

    sleep(seconds)

    print('wait', seconds, 'seconds, time is', datetime.utcnow())

 

if __name__ == '__main__':

    import random

    for n in range(3):

        seconds = random.random()

        proc = multiprocessing.Process(target=now, args=(seconds,))

        proc.start()

 

$ python multi_times.py

wait 0.10720361113059229 seconds, time is 2019-07-24 00:19:23.951594

wait 0.5825144002370065 seconds, time is 2019-07-24 00:19:24.425047

wait 0.6647690569029477 seconds, time is 2019-07-24 00:19:24.509995

16. Данные в коробке: устойчивые хранилища

16.1. Сохраните следующие несколько строк в файл books.csv. Обратите внимание на то, что, если поля разделены запятыми, вам нужно заключить в кавычки поле, содержащее запятую:

author,book

J R R Tolkien,The Hobbit

Lynne Truss,"Eats, Shoots & Leaves"

>>> text = '''author,book

... J R R Tolkien,The Hobbit

... Lynne Truss,"Eats, Shoots & Leaves"

... '''

>>> with open('test.csv', 'wt') as outfile:

...     outfile.write(text)

...

73

16.2. Используйте модуль csv и его метод DictReader, чтобы считать содержимое файла books.csv в переменную books. Выведите на экран значения переменной books. Обработал ли метод DictReader кавычки и запятые в заголовке второй книги?

>>> with open('books.csv', 'rt') as infile:

...     books = csv.DictReader(infile)

...     for book in books:

...         print(book)

...

{'book': 'The Hobbit', 'author': 'J R R Tolkien'}

{'book': 'Eats, Shoots & Leaves', 'author': 'Lynne Truss'}

16.3. Создайте CSV-файл books.csv и запишите его в следующие строки.

title,author,year

The Weirdstone of Brisingamen,Alan Garner,1960

Perdido Street Station,China Miéville,2000

Thud!,Terry Pratchett,2005

The Spellman Files,Lisa Lutz,2007

Small Gods,Terry Pratchett,1992

>>> text = '''title,author,year

... The Weirdstone of Brisingamen,Alan Garner,1960

...    Perdido Street Station,China Miéville,2000

...    Thud!,Terry Pratchett,2005

...    The Spellman Files,Lisa Lutz,2007

... Small Gods,Terry Pratchett,1992

... '''

>>> with open('books2.csv', 'wt') as outfile:

...     outfile.write(text)

...

201

16.4. Используйте модуль sqlite3, чтобы создать базу данных SQLite books.db и таблицу books, содержащую следующие поля: title (текст), author (текст) и year (целое значение).

>>> import sqlite3

>>> db = sqlite3.connect('books.db')

>>> curs = db.cursor()

>>> curs.execute('''create table book (title text, author text, year int)''')

<sqlite3.Cursor object at 0x1006e3b90>

>>> db.commit()

16.5. Считайте данные из файла books2.csv и добавьте их в таблицу book.

>>> import csv

>>> import sqlite3

>>> ins_str = 'insert into book values(?, ?, ?)'

>>> with open('books.csv', 'rt') as infile:

...   books = csv.DictReader(infile)

...   for book in books:

...     curs.execute(ins_str, (book['title'], book['author'], book['year']))

...

<sqlite3.Cursor object at 0x1007b21f0>

<sqlite3.Cursor object at 0x1007b21f0>

<sqlite3.Cursor object at 0x1007b21f0>

<sqlite3.Cursor object at 0x1007b21f0>

<sqlite3.Cursor object at 0x1007b21f0>

>>> db.commit()

16.6. Считайте и выведите на экран столбец title таблицы book в алфавитном порядке.

>>> sql = 'select title from book order by title asc'

>>> for row in db.execute(sql):

...     print(row)

...

('Perdido Street Station',)

('Small Gods',)

('The Spellman Files',)

('The Weirdstone of Brisingamen',)

('Thud!',)

Если вы хотите вывести на экран значение title, не пользуясь конструкциями для работы с кортежем (круглыми скобками и запятой), то попробуйте следующее:

>>> for row in db.execute(sql):

...     print(row[0])

...

Perdido Street Station

Small Gods

The Spellman Files

The Weirdstone of Brisingamen

Thud!

Если хотите проигнорировать начальное слово 'The' в заголовках, то вам нужно написать еще одну строку SQL:

>>> sql = '''select title from book order by

... case when (title like "The %")

... then substr(title, 5)

... else title end'''

>>> for row in db.execute(sql):

...     print(row[0])

...

Perdido Street Station

Small Gods

The Spellman Files

Thud!

The Weirdstone of Brisingamen

16.7. Считайте и выведите на экран все столбцы таблицы book в порядке публикации.

>>> for row in db.execute('select * from book order by year'):

...     print(row)

...

('The Weirdstone of Brisingamen', 'Alan Garner', 1960)

('Small Gods', 'Terry Pratchett', 1992)

('Perdido Street Station', 'China Miéville', 2000)

('Thud!', 'Terry Pratchett', 2005)

('The Spellman Files', 'Lisa Lutz', 2007)

Чтобы вывести на экран все столбцы каждой строки, просто разделите их запятой и пробелом:

>>> for row in db.execute('select * from book order by year'):

...     print(*row, sep=', ')

...

The Weirdstone of Brisingamen, Alan Garner, 1960

Small Gods, Terry Pratchett, 1992

Perdido Street Station, China Miéville, 2000

Thud!, Terry Pratchett, 2005

The Spellman Files, Lisa Lutz, 2007

16.8. Используйте модуль sqlalchemy, чтобы подключиться к базе данных sqlite3books.db, которую вы создали в упражнении 16.4. Как и в упражнении 16.6, считайте и выведите на экран столбец title таблицы book в алфавитном порядке.

>>> import sqlalchemy

>>> conn = sqlalchemy.create_engine('sqlite:///books.db')

>>> sql = 'select title from book order by title asc'

>>> rows = conn.execute(sql)

>>> for row in rows:

...     print(row)

...

('Perdido Street Station',)

('Small Gods',)

('The Spellman Files',)

('The Weirdstone of Brisingamen',)

('Thud!',)

16.9. Установите сервер Redis и библиотеку Python redis (с помощью команды pipinstallredis) на свой компьютер. Создайте хеш redis с именем test, содержащий поля count(1) и name('FesterBestertester'). Выведите все поля хеша test.

>>> import redis

>>> conn = redis.Redis()

>>> conn.delete('test')

1

>>> conn.hmset('test', {'count': 1, 'name': 'Fester Bestertester'})

True

>>> conn.hgetall('test')

{b'name': b'Fester Bestertester', b'count': b'1'}

16.10. Увеличьте поле count хеша test и выведите его на экран.

>>> conn.hincrby('test', 'count', 3)

4

>>> conn.hget('test', 'count')

b'4'

17. Данные в пространстве: сети

17.1. Используйте объект класса socket, чтобы реализовать сервис, сообщающий текущее время. Когда клиент отправляет на сервер строку 'time', верните текущие дату и время как строку ISO.

Вот так можно написать сервер udp_time_server.py:

from datetime import datetime

import socket

 

address = ('localhost', 6789)

max_size = 4096

 

print('Starting the server at', datetime.now())

print('Waiting for a client to call.')

server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

server.bind(address)

while True:

    data, client_addr = server.recvfrom(max_size)

    if data == b'time':

        now = str(datetime.utcnow())

        data = now.encode('utf-8')

        server.sendto(data, client_addr)

        print('Server sent', data)

server.close()

А так — клиент udp_time_client.py:

import socket

from datetime import datetime

from time import sleep

 

address    = ('localhost', 6789)

max_size   = 4096

 

print('Starting the client at', datetime.now())

client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:

    sleep(5)

    client.sendto(b'time', address)

    data, server_addr = client.recvfrom(max_size)

    print('Client read', data)

client.close()

Я поместил вызов sleep(5) в верхней части цикла клиента, чтобы сделать обмен данными менее быстрым. Запустите сервер в одном окне:

$ python udp_time_server.py

Starting the server at 2014-06-02 20:28:47.415176

Waiting for a client to call.

Запустите клиент в другом окне:

$ python udp_time_client.py

Starting the client at 2014-06-02 20:28:51.454805

Через 5 секунд вы начнете видеть сообщения в обоих окнах. Так выглядят первые три строки от сервера:

Server sent b'2014-06-03 01:28:56.462565'

Server sent b'2014-06-03 01:29:01.463906'

Server sent b'2014-06-03 01:29:06.465802'

А так — первые три строки от клиента:

Client read b'2014-06-03 01:28:56.462565'

Client read b'2014-06-03 01:29:01.463906'

Client read b'2014-06-03 01:29:06.465802'

Обе программы работают вечно, поэтому вам нужно завершать их вручную.

17.2. Задействуйте сокеты ZeroMQ REQ и REP, чтобы сделать то же самое.

import zmq

from datetime import datetime

host = '127.0.0.1'

port = 6789

context = zmq.Context()

server = context.socket(zmq.REP)

server.bind("tcp://%s:%s" % (host, port))

print('Server started at', datetime.utcnow())

while True:

    #  ожидаем следующего запроса от клиента

    message = server.recv()

    if message == b'time':

        now = datetime.utcnow()

        reply = str(now)

        server.send(bytes(reply, 'utf-8'))

        print('Server sent', reply)

 

import zmq

from datetime import datetime

from time import sleep

 

host = '127.0.0.1'

port = 6789

context = zmq.Context()

client = context.socket(zmq.REQ)

client.connect("tcp://%s:%s" % (host, port))

print('Client started at', datetime.utcnow())

while True:

    sleep(5)

    request = b'time'

    client.send(request)

    reply = client.recv()

    print("Client received %s" % reply)

Для простых сокетов вам нужно сначала запустить сервер. С помощью ZeroMQ вы можете запустить первым как клиент, так и сервер:

$ python zmq_time_server.py

Server started at 2014-06-03 01:39:36.933532

$ python zmq_time_client.py

Client started at 2014-06-03 01:39:42.538245

Через 15 секунд вы должны увидеть сообщения от сервера:

Server sent 2014-06-03 01:39:47.539878

Server sent 2014-06-03 01:39:52.540659

Server sent 2014-06-03 01:39:57.541403

Эти строки вы должны увидеть в сообщении от клиента:

Client received b'2014-06-03 01:39:47.539878'

Client received b'2014-06-03 01:39:52.540659'

Client received b'2014-06-03 01:39:57.541403'

17.3. Попробуйте сделать то же самое с помощью XMLRPC.

С сервера:

from xmlrpc.server import SimpleXMLRPCServer

 

def now():

    from datetime import datetime

    data = str(datetime.utcnow())

    print('Server sent', data)

    return data

 

server = SimpleXMLRPCServer(("localhost", 6789))

server.register_function(now, "now")

server.serve_forever()

С клиента:

import xmlrpc.client

from time import sleep

 

proxy = xmlrpc.client.ServerProxy("/")

while True:

    sleep(5)

    data = proxy.now()

    print('Client received', data)

Запустим сервер:

$ python xmlrpc_time_server.py

Запустим клиент:

$ python xmlrpc_time_client.py

Подождите примерно 15 секунд. Так выглядят первые три строки от сервера:

Server sent 2014-06-03 02:14:52.299122

127.0.0.1 - - [02/Jun/2014 21:14:52] "POST / HTTP/1.1" 200 -

Server sent 2014-06-03 02:14:57.304741

127.0.0.1 - - [02/Jun/2014 21:14:57] "POST / HTTP/1.1" 200 -

Server sent 2014-06-03 02:15:02.310377

127.0.0.1 - - [02/Jun/2014 21:15:02] "POST / HTTP/1.1" 200 -

А так — первые три строки от клиента:

Client received 2014-06-03 02:14:52.299122

Client received 2014-06-03 02:14:57.304741

Client received 2014-06-03 02:15:02.310377

17.4. Возможно, вы видели эпизод телесериала I Love Lucy, в котором Люси и Этель работают на шоколадной фабрике. Парочка стала отставать, когда линия конвейера, направлявшая к ним на обработку конфеты, еще более ускорилась. Напишите симуляцию, которая отправляет разные типы конфет в список Redis, и клиент Lucy, делающий блокирующие выталкивания из списка. Ей нужно 0,5 секунды, чтобы обработать одну конфету. Выведите на экран время и тип каждой конфеты, которую получит Lucy, а также количество необработанных конфет:

Симуляция redis_choc_supply.py передает бесконечное количество конфет:

import redis

import random

from time import sleep

 

conn = redis.Redis()

varieties = ['truffle', 'cherry', 'caramel', 'nougat']

conveyor = 'chocolates'

while True:

    seconds = random.random()

    sleep(seconds)

    piece = random.choice(varieties)

    conn.rpush(conveyor, piece)

Клиент redis_lucy.py может выглядеть так:

import redis

from datetime import datetime

from time import sleep

 

conn = redis.Redis()

timeout = 10

conveyor = 'chocolates'

while True:

    sleep(0.5)

    msg = conn.blpop(conveyor, timeout)

    remaining = conn.llen(conveyor)

    if msg:

        piece = msg[1]

        print('Lucy got a', piece, 'at', datetime.utcnow(),

        ', only', remaining, 'left')

Запустите их в любом порядке. Поскольку Люси требуется 0,5 секунды для обработки каждой конфеты и они появляются в среднем каждые 0,5 секунды, это становится похоже на гонку. Чем раньше вы запустите конвейер, тем более сложной сделаете жизнь Люси:

$ python redis_choc_supply.py &

 

$ python redis_lucy.py

Lucy got a b'nougat' at 2014-06-03 03:15:08.721169 , only 4 left

Lucy got a b'cherry' at 2014-06-03 03:15:09.222816 , only 3 left

Lucy got a b'truffle' at 2014-06-03 03:15:09.723691 , only 5 left

Lucy got a b'truffle' at 2014-06-03 03:15:10.225008 , only 4 left

Lucy got a b'cherry' at 2014-06-03 03:15:10.727107 , only 4 left

Lucy got a b'cherry' at 2014-06-03 03:15:11.228226 , only 5 left

Lucy got a b'cherry' at 2014-06-03 03:15:11.729735 , only 4 left

Lucy got a b'truffle' at 2014-06-03 03:15:12.230894 , only 6 left

Lucy got a b'caramel' at 2014-06-03 03:15:12.732777 , only 7 left

Lucy got a b'cherry' at 2014-06-03 03:15:13.234785 , only 6 left

Lucy got a b'cherry' at 2014-06-03 03:15:13.736103 , only 7 left

Lucy got a b'caramel' at 2014-06-03 03:15:14.238152 , only 9 left

Lucy got a b'cherry' at 2014-06-03 03:15:14.739561 , only 8 left

Бедная Люси.

17.5. Используйте ZeroMQ, чтобы публиковать стихотворение из упражнения 12.4 (пример 12.1) по одному слову за раз. Напишите потребитель ZeroMQ, который будет выводить на экран каждое слово, начинающееся с гласной. Напишите другой потребитель, который станет выводить все слова, состоящие из пяти букв. Знаки препинания игнорируйте.

Так выглядит сервер 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 ().

18. Распутываем Всемирную паутину

18.1. Если вы еще не установили Flask, то сделайте это сейчас. Это также позволит установить werkzeug, jinja2 и, возможно, другие пакеты.

18.2. Создайте скелет сайта с помощью веб-сервера Flask. Убедитесь, что сервер начинает свою работу по адресу Localhost на стандартном порте 5000. Если ваш компьютер уже использует этот порт для чего-то еще, то воспользуйтесь другим портом.

Так выглядит файл flask1.py:

from flask import Flask

 

app = Flask(__name__)

 

app.run(port=5000, debug=True)

Поехали:

$ python flask1.py

* Running on /

* Restarting with reloader

18.3. Добавьте функцию home() для обработки запросов к главной странице. Пусть она возвращает строку It'salive!.

Как нам назвать этот файл, flask2.py?

from flask import Flask

 

app = Flask(__name__)

 

@app.route('/')

def home():

    return "It's alive!"

 

app.run(debug=True)

Запустим сервер:

$ python flask2.py

* Running on /

* Restarting with reloader

Наконец, получим доступ к главной странице через браузер, HTTP-программы командной строки, такие как curl, или wget, или даже telnet:

$ curl /

It's alive!

18.4. Создайте шаблон для jinja2, который называется home.html и содержит следующий контент:

<html>

<head>

<title>It's alive!</title>

<body>

I'm of course referring to {{thing}}, which is {{height}} feet tall and {{color}}.

</body>

</html>

Создайте каталог templates и файл home.html, содержащий показанное. Если ваш сервер Flask все еще работает после запуска предыдущих примеров, то обнаружит новый контент и перезапустится.

18.5. Модифицируйте функцию home() вашего сервера, чтобы она использовала шаблон home.html. Передайте ей три параметра для команды GET: thing, height и color.

Перед вами файл flask3.py:

from flask import Flask, request, render_template

 

app = Flask(__name__)

 

@app.route('/')

def home():

    thing = request.values.get('thing')

    height = request.values.get('height')

    color = request.values.get('color')

    return render_template('home.html',

        thing=thing, height=height, color=color)

 

app.run(debug=True)

Перейдите в своем клиенте по следующему адресу:

Вы должны увидеть вот что:

I'm of course referring to Octothorpe, which is 7 feet tall and green.

19. Быть питонщиком

Питонщикам сегодня ничего не задавали.

20. Пи-Арт

20.1. Установите matplotlib. Нарисуйте диаграмму рассеивания для следующих пар (x,y): ((0,0), (3,5), (6,2), (9,8), (14,10)).

20.2. Нарисуйте линейчатый график на основе тех же данных.

20.3. Нарисуйте график на основе тех же данных.

В этом фрагменте кода показаны все три подграфика:

import matplotlib.pyplot as plt

 

x = (0, 3, 6, 9, 14)

y = (0, 5, 2, 8, 10)

fig, plots = plt.subplots(nrows=1, ncols=3)

 

plots[0].scatter(x, y)

plots[1].plot(x, y)

plots[2].plot(x, y, 'o-')

 

plt.show()

21. За работой

21.1. Установите Geopandas и запустите пример 21.1. Попробуйте поизменять цвета и размеры меток.

22. Python в науке

22.1. Установите Pandas. Получите CSV-файл в примере 16.1. Запустите программу из примера 16.2. Поэкспериментируйте с командами Pandas.

Назад: Приложение В. Нечто совершенно иное: async
Дальше: Приложение Д. Вспомогательные таблицы

dofermerdat
этот. породы кроликов с фотографиями мясныефермер ру форум рассадакрупнейшие сельскохозяйственные районы зарубежной европыкрс мясо