[英]Python 2 & 3 compatibility with `super` and classes who were old-style in Py2 but became new-style in Py3
I have a project which uses SafeConfigParser
and I want it to be Python2 and 3 compatible. 我有一个使用
SafeConfigParser
的项目 ,我希望它与Python2和3兼容。 Now, SafeConfigParser
is deprecated since Python 3.2 and I find the deprecation warning annoying. 现在,从Python 3.2开始不推荐使用
SafeConfigParser
,我发现弃用警告很烦人。 So I went about my business to remedy that. 所以我开始做我的事来解决这个问题。
First (and much older, already solved problem): SafeConfigParser
is an old-style class in Python2 so I cannot call super
in my descendant class. 首先(和更老的,已经解决的问题):
SafeConfigParser
是SafeConfigParser
中的旧式类,所以我不能在我的后代类中调用super
。 To have a more consistent behaviour, I wrote the following: 为了获得更一致的行为,我写了以下内容:
try:
# Python 2
class ConfigResolverBase(object, SafeConfigParser):
"""
A default "base" object simplifying Python 2 and Python 3
compatibility.
"""
pass
except TypeError:
# Python 3
class ConfigResolverBase(SafeConfigParser):
"""
A default "base" object simplifying Python 2 and Python 3
compatibility.
"""
pass
This worked fine to make the class new-style if necessary. 如果有必要,这样可以使课程成为新式。 To get rid of the
DeprecationWarning
I changed the code into this: 为了摆脱
DeprecationWarning
我将代码更改为:
if sys.hexversion < 0x030000F0:
# Python 2
class ConfigResolverBase(object, SafeConfigParser):
"""
A default "base" object simplifying Python 2 and Python 3
compatibility.
"""
pass
else:
# Python 3
class ConfigResolverBase(ConfigParser):
"""
A default "base" object simplifying Python 2 and Python 3
compatibility.
"""
pass
Along the way I also fixed a line I missed to change earlier: 一路上我还修了一条我错过了之前改变的路线:
@@ -275,7 +276,7 @@ class Config(ConfigResolverBase):
have_default = False
try:
- value = SafeConfigParser.get(self, section, option, **kwargs)
+ value = super(Config, self).get(section, option, **kwargs)
return value
except (NoSectionError, NoOptionError) as exc:
if have_default:
And that change caused an interesting error: 而这一变化引发了一个有趣的错误:
AttributeError: 'Config' object has no attribute '_sections'
Which let me to believe that __init__
of ConfigParser
was not called. 让我相信
ConfigParser
__init__
没有被调用。 And indeed making the following change fixed that: 确实做出以下修改:
- class ConfigResolverBase(object, SafeConfigParser):
+ class ConfigResolverBase(SafeConfigParser, object):
My code is now working fine for both Python 2 and 3, but whant I am unsure about is: Is the proxy returned by super
always the same?" In my case I inherit from both object
and SafeConfigParser
. Swapping the two bases in my class definition made super
return the right one. But is this guaranteed to be stable across all Python implementations on all platforms? Or should I explicitly call SafeConfigParser.get(self, ...)
? Which is after-all the "old way" of calling the base... 我的代码现在对Python 2和3都运行良好,但我不确定的是:
super
返回的代理总是一样的吗?“在我的情况下,我继承了object
和SafeConfigParser
。在我的类中交换两个SafeConfigParser
定义使super
返回正确的。但这是否保证在所有平台上的所有Python实现中都是稳定的?或者我应该明确地调用SafeConfigParser.get(self, ...)
?这是所有的“老方法”呼唤基地......
Yes, it is guaranteed stable across Python versions. 是的,它在Python版本中保证稳定。 The search order is called the Method Resolution Order, or MRO, and this order has been the same since Python 2.3.
搜索顺序称为方法解析顺序(MRO),此顺序与Python 2.3相同。
For more details on how the order is determined, see the Python 2.3 Method Resolution Order documentation . 有关如何确定订单的更多详细信息,请参阅Python 2.3方法解析订单文档 。
You can inspect the MRO by looking at the .__mro__
attribute of a given class; 您可以通过查看给定类的
.__mro__
属性来检查MRO; it is a tuple of the classes in method-resolution order. 它是方法解析顺序中的类的元组。
I was also doing some work using SafeConfigParser
. 我也在使用
SafeConfigParser
做一些工作。 To make it work with old-style and new-style classes, both, you can check if it is a subclass of object
or not. 为了使它适用于旧式和新式类,两者都可以检查它是否是
object
的子类。 New-style classes inherit from object
, whereas old-style classes don't. 新式类继承自
object
,而旧式类则不继承。
Example: 例:
class MyClass(SafeConfigParser):
def __init__(self):
if issubclass(SafeConfigParser, object):
# new style class, call super
super(MyClass, self).__init__()
else:
# old style class, call __init__ manually
SafeConfigParser.__init__(self)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.