TypeError: super(type, obj): obj must be an instance or subtype of type

一时失言乱红尘 2022-01-16 07:21 443阅读 0赞

问题

今天学习《Python Web 开发实战》自定义转换器这一小节,书中有段代码如下:

  1. class ListConverter(BaseConverter):
  2. def __init__(self, url_map, separator="+"):
  3. super(ListConverter, self).__init__(url_map)
  4. self.separator = urllib.parse.unquote(separator)
  5. def to_python(self, value):
  6. return value.split(self.separator)
  7. def to_url(self, values):
  8. return self.separator.join(super(ListConverter, self).to_url(value)
  9. for value in values)

倒没什么问题,是可以正常运行的。

然而我对 super() 的用法不是很满意,毕竟在 Python3 环境下开发,super(ListConverter, self) 有硬编码嫌疑。于是代码修改如下:

  1. class ListConverter(BaseConverter):
  2. def __init__(self, url_map, separator="+"):
  3. super().__init__(url_map)
  4. self.separator = urllib.parse.unquote(separator)
  5. def to_python(self, value):
  6. return value.split(self.separator)
  7. def to_url(self, values):
  8. return self.separator.join(super().to_url(value)
  9. for value in values)

结果一运行,解释器报错如下:
TypeError: super(type, obj): obj must be an instance or subtype of type

原因

经过多次尝试,发现问题出现在 self.separator.join(super().to_url(value) for value in values) 这段代码里。于是我做了个测试。

  1. class A(object):
  2. def print_what(self, what):
  3. print(what)
  4. class B(A):
  5. def print_what(self, what):
  6. [super() for __ in range(5)]
  7. if __name__ == "__main__":
  8. b = B()
  9. b.print_what("hello")
  10. ------------------------------------
  11. TypeError: super(type, obj): obj must be an instance or subtype of type

果然异常,当我将 super() 改为 super(B, self) 又一切正常。

是因为 super() 在一个成员函数中多次调用造成的吗?那就不用列表解析式,换寻常的循环语句:

  1. class B(A):
  2. def print_what(self, what):
  3. for __ in range(5):
  4. super()

结果运行正常。

事实上,在成员函数中使用 super() 时,Python 会自动传参,我猜测是解析式影响了传进去的参数。但遗憾的是,我不知道该如何调试,才能获得错误情况下,传进去的参数是什么。

解决方案

针对此次遇到的问题,解决方法有以下三种。

第一种

使用 super(ListConverter, self) 代替 super()

第二种

不用解析式,用寻常的 for 循环。

  1. class ListConverter(BaseConverter):
  2. ...
  3. def to_url(self, values):
  4. tmplist = []
  5. for value in values:
  6. tmplist.append(super().to_url(value))
  7. return self.separator.join(tmplist)

第三种

使用解析式,但不在解析式中调用 super()。

  1. class ListConverter(BaseConverter):
  2. ...
  3. def to_url(self, values):
  4. sup = super()
  5. return self.separator.join(sup.to_url(value)
  6. for value in values)

发表评论

表情:
评论列表 (有 0 条评论,443人围观)

还没有评论,来说两句吧...

相关阅读