我正在使用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):
答案 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