当这个变量被self覆盖时,变量会发生什么?

时间:2011-02-25 21:01:27

标签: python

我正在使用Python下载网址并需要检测404,所以经过一些搜索后我想出了:

import urllib
class MyUrlOpener(urllib.FancyURLopener):
    def retrieve(self, url, filename=None, reporthook=None, data=None):
        self.file_was_found = True
        val = urllib.FancyURLopener.retrieve(self, url, filename, reporthook, data)        
        return val

    def http_error_404(url, fp, errcode, errmsg, headers, data):
        url.file_was_found = False


def download_file(url, saveas):
    urlaccess = MyUrlOpener()
    localFile, headers = urlaccess.retrieve(url, saveas)
    return urlaccess.file_was_found

我的问题是,如果您查看FancyURLopener的源代码(Python 2.7),那么您会看到:

def http_error(self, url, fp, errcode, errmsg, headers, data=None):
    """Handle http errors.
    Derived class can override this, or provide specific handlers
    named http_error_DDD where DDD is the 3-digit error code."""
    # First check if there's a specific handler for this error
    name = 'http_error_%d' % errcode
    if hasattr(self, name):
        method = getattr(self, name)
        if data is None:
            result = method(url, fp, errcode, errmsg, headers)
        else:
            result = method(url, fp, errcode, errmsg, headers, data)
        if result: return result
    return self.http_error_default(url, fp, errcode, errmsg, headers)

哪个传递url作为第一个参数,而不是self。我认为函数的第一个参数始终是对类实例的引用(按照惯例),我的代码确认了这一点。那么url值会发生什么?

更新:结果是data==None所以它正在调用第一个签名。这挫败了我手动添加self参数的尝试。我在=None签名中添加data默认设置http_error_404后,一切都很顺利(因为它使用了默认设置)。

已修复 / 正确的签名为def http_error_404(self, url, fp, errcode, errmsg, headers, data=None):

2 个答案:

答案 0 :(得分:3)

在Python中,任何类实例的方法都有self由Python解释器传入,所有其他参数都自动向下移动一个位置。

换句话说,Python解释器重写:

urlaccess.retrieve(url, saveas)

看起来像这样:

urlaccess.retrieve(urlaccess, url, saveas)

所以你不必自己动手。但是,因为

  

显式优于隐式

您为Python对象声明的任何实例方法都必须指定显式,它们将对象的实例作为其第一个参数,即使Python将传递该参数而不对该部分执行任何操作程序员。

第一个参数没有被称为self ......这只是一个惯例。


所以,要实际回答你的问题(正如mluebke所做的那样) - 你需要指定self参数。

def http_error_404(url, fp, errcode, errmsg, headers, data):
    url.file_was_found = False
    # Python is treating `url` as `self`
    # Therefore the URL is being saved in `fp`, `fp` in `errcode`, etc.

要解决此问题,请添加第一个参数以获取实例。

def http_error_404(self, url, fp, errcode, errmsg, headers, data):
    self.file_was_found = False
    # Now everything should work

答案 1 :(得分:3)

self在方法定义中明确列出,但在调用方法时隐式传递。将您的功能更改为这样,所有变量将再次开始排列。

def http_error_404(self, url, fp, errcode, errmsg, headers, data):
    self.file_was_found = False