简体   繁体   English

Python 2和3兼容`super`和类在Py2中是旧式的,但在Py3中变成了新式

[英]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. 首先(和更老的,已经解决的问题): SafeConfigParserSafeConfigParser中的旧式类,所以我不能在我的后代类中调用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返回的代理总是一样的吗?“在我的情况下,我继承了objectSafeConfigParser 。在我的类中交换两个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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM