Python 回溯:AttributeError:addinfourl 实例没有属性“__exit__”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30627937/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 08:43:28  来源:igfitidea点击:

Traceback: AttributeError:addinfourl instance has no attribute '__exit__'

pythonpython-2.7

提问by Brenda Olivia Martis

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)

Error message:

错误信息:

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

I am not understanding what's wrong with the above code and how to resolve it?

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

System information : python 2.7 in ubuntu oracle virtual box.

系统信息:ubuntu oracle virtual box 中的python 2.7。

采纳答案by xyres

That error is caused by this line:

该错误是由这一行引起的:

with urlopen('https://www.python.org') as story:

You can't use any random object in a with...asstatement.

您不能在with...as语句中使用任何随机对象。

There are two ways to fix this:

有两种方法可以解决这个问题:

Solution 1:Use contextlib.closing:

解决方案1:使用contextlib.closing

from contextlib import closing

with closing(urlopen('https://www.python.org')) as story:
    ...

Solution 2:Don't use a with...asstatement; instead assign the value to a variable:

解决方案2:不要使用with...as语句;而是将值分配给变量:

story = urlopen('https://www.python.org')
...


Why is this happening?

为什么会这样?

You can't use any random object in a with ... asstatement.

您不能在with ... as语句中使用任何随机对象。

Only those objects will work which have two magic methods: __enter__and __exit__implemented on them. Collectively, these methods are called "context manager". An introductory tutorial about this can be found below.

只有那些具有两个魔术方法的对象才能工作:__enter____exit__在它们上实现。这些方法统称为“上下文管理器”。可以在下面找到有关此的介绍性教程。

The AttributeErrorwas raised because there isn't any context manager implemented for urlopen(i.e.it doesn't have __enter__and __exit__methods defined for it).

之所以AttributeError被提出,是因为没有为其实现任何上下文管理器urlopen它没有为它定义__enter____exit__方法)。

This leaves you with two choices:

这让您有两个选择:

  1. either don't use with...asstatement.
  2. or use contextlib.closing(thanks to @vaultahwho provided this solution in a comment below). It automatically implements context manager for any object, thereby allowing you to use with...asstatement.
  1. 要么不使用with...as声明。
  2. 或使用contextlib.closing(感谢@vaultah在下面的评论中提供了此解决方案)。它自动为任何对象实现上下文管理器,从而允许您使用with...as语句。

(Note: In Python 3, urlopendoes have a context manager, and thus can be used in a with...asstatement.)

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



Tutorial: How to implement the context manager?

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

To make an object work in a with...asstatement, you first need to implement the context manager for that object. In simpler terms, you need to define __enter__and __exit__methods for that object/class.

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

Do read these docs on context managers.

请阅读有关上下文管理器的这些文档

Example:

例子:

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

回答by shruti1810

You can try the following in Python 2.7:

您可以在 Python 2.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)