问题
今天学习《Python Web 开发实战》自定义转换器这一小节,书中有段代码如下:
class ListConverter(BaseConverter):
def __init__(self, url_map, separator="+"):
super(ListConverter, self).__init__(url_map)
self.separator = urllib.parse.unquote(separator)
def to_python(self, value):
return value.split(self.separator)
def to_url(self, values):
return self.separator.join(super(ListConverter, self).to_url(value)
for value in values)
倒没什么问题,是可以正常运行的。
然而我对 super()
的用法不是很满意,毕竟在 Python3 环境下开发,super(ListConverter, self) 有硬编码嫌疑。于是代码修改如下:
class ListConverter(BaseConverter):
def __init__(self, url_map, separator="+"):
super().__init__(url_map)
self.separator = urllib.parse.unquote(separator)
def to_python(self, value):
return value.split(self.separator)
def to_url(self, values):
return self.separator.join(super().to_url(value)
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) 这段代码里。于是我做了个测试。
class A(object):
def print_what(self, what):
print(what)
class B(A):
def print_what(self, what):
[super() for __ in range(5)]
if __name__ == "__main__":
b = B()
b.print_what("hello")
------------------------------------
TypeError: super(type, obj): obj must be an instance or subtype of type
果然异常,当我将 super() 改为 super(B, self)
又一切正常。
是因为 super() 在一个成员函数中多次调用造成的吗?那就不用列表解析式,换寻常的循环语句:
class B(A):
def print_what(self, what):
for __ in range(5):
super()
结果运行正常。
事实上,在成员函数中使用 super() 时,Python 会自动传参,我猜测是解析式影响了传进去的参数。但遗憾的是,我不知道该如何调试,才能获得错误情况下,传进去的参数是什么。
解决方案
针对此次遇到的问题,解决方法有以下三种。
第一种
使用 super(ListConverter, self)
代替 super()
第二种
不用解析式,用寻常的 for 循环。
class ListConverter(BaseConverter):
...
def to_url(self, values):
tmplist = []
for value in values:
tmplist.append(super().to_url(value))
return self.separator.join(tmplist)
第三种
使用解析式,但不在解析式中调用 super()。
class ListConverter(BaseConverter):
...
def to_url(self, values):
sup = super()
return self.separator.join(sup.to_url(value)
for value in values)
还不快抢沙发