Skip to main content
 首页 » 编程设计

python之在这种情况下,当变量被 self 覆盖时会发生什么

2025年05月04日16落叶

我正在用 Python 下载 URL 并且需要检测 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 参数的尝试。在我的 http_error_404 签名中将 =None 默认值添加到 data 后,一切都很好(因为它使用了默认值)。

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

请您参考如下方法:

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

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

urlaccess.retrieve(url, saveas) 

变成这样的东西:

urlaccess.retrieve(urlaccess, url, saveas) 

所以你不必自己做。然而,由于

explicit is better than implicit

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