Ответ 1
Эта ошибка вызвана этой строкой:
with urlopen('https://www.python.org') as story:
Вы не можете использовать какой-либо случайный объект в выражении with...as
.
Есть два способа это исправить:
Решение 1: Используйте contextlib.closing
:
from contextlib import closing
with closing(urlopen('https://www.python.org')) as story:
...
Решение 2: Не используйте оператор with...as
; вместо этого присвойте значение переменной:
story = urlopen('https://www.python.org')
...
Почему это происходит?
Вы не можете использовать любой случайный объект в выражении with ... as
.
Будут работать только те объекты, у которых есть два магических метода: __enter__
и __exit__
. В совокупности эти методы называются "диспетчер контекста". Вводное руководство по этому вопросу можно найти ниже.
AttributeError
был вызван, потому что для urlopen
не реализован менеджер контекста (т.е. для него не определены методы __enter__
и __exit__
).
Это оставляет вам два варианта:
- либо не используйте оператор
with...as
. - или используйте
contextlib.closing
(спасибо @vaultah, который предоставил это решение в комментарии ниже). Он автоматически реализует диспетчер контекста для любого объекта, что позволяет вам использовать операторwith...as
.
(Примечание: в Python 3 у urlopen
есть менеджер контекста, и поэтому его можно использовать в операторе with...as
.)
Учебник. Как реализовать менеджер контекста?
Чтобы заставить объект работать в операторе with...as
, сначала необходимо реализовать менеджер контекста для этого объекта. Проще говоря, вам нужно определить методы __enter__
и __exit__
для этого объекта/класса.
Прочитайте эти документы по менеджерам контекста.
Пример:
>>> class Person(object):
"""To implement context manager, just create two methods
__enter__ and __exit__.
"""
def __init__(self, name):
self.name = name
def __enter__(self):
# The value returned by this method is
# assigned to the variable after ''as''
return self
def __exit__(self, exc_type, exc_value, exc_traceback ):
# returns either True or False
# Don't raise any exceptions in this method
return True
>>> with Person("John Doe") as p:
print p.name
>>> "John Doe" #success