追溯:属性错误:addinfourl实例没有属性“__exit__”

2024-06-05 23:40:49 发布

您现在位置:Python中文网/ 问答频道 /正文

from urllib import urlopen
with urlopen('https://www.python.org') as story:
    story_words = []
    for line in story:
        line_words = line.split()
        for words in line_words:
            story_words.append(word)

错误消息:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: addinfourl instance has no attribute '__exit__'

我不明白上面的代码有什么问题以及如何解决?

系统信息:ubuntu oracle虚拟框中的python 2.7。


Tags: infromhttpsorgimportforaswww
2条回答

您可以在Python2.7中尝试以下操作:

from urllib import urlopen
story = urlopen('https://www.python.org')
story_words = []
for line in story:
    line_words = line.split()
    for words in line_words:
        story_words.append(words)

该错误是由以下行引起的:

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__方法)。

这让您有两个选择:

  1. 或者不使用with...as语句。
  2. 或者使用^{}(感谢@vaultah在下面的注释中提供了这个解决方案)。它自动为任何对象实现上下文管理器,从而允许您使用with...as语句。

(注意:在Python 3中,urlopen没有上下文管理器,因此可以在with...as语句中使用。)


教程:如何实现上下文管理器?

要使对象在with...as语句中工作,首先需要实现该对象的上下文管理器。简单地说,您需要为该对象/类定义__enter____exit__方法。

一定要读these docs on context managers

示例:

>>> 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

相关问题 更多 >