如何将 `__slots__` 从 Python 2 移植到 3

How to port `__slots__` from Python 2 to 3

我必须将遗留代码(~60K LOC)从 Python 2 移植到 3,它有几千个结构,如下所示:

class Sample(object):
    __slots__ = ('both', 'advertise')
    class __metaclass__(type):
        __instancecheck__ = classmethod(
                lambda cls, inst: inst in ('both', 'advertise'))
    both = 'both'
    advertise = 'advertise'

此代码在 Python 2 上运行良好,但无法在 Python 3 下编译,要解决它,我需要将其更改为

class Sample(object):
    __slots__ = ('both', 'advertise')
    class __metaclass__(type):
        __instancecheck__ = classmethod(
                lambda cls, inst: inst in ('both', 'advertise'))
    def __init__(self):
        both = 'both'
        advertise = 'advertise'

考虑到必须对如此大的文件多次执行此更改,处理此更改的有效方法是什么?

我们必须考虑到 class 可能已经有也可能没有 __init__ 函数定义,并且也可以有嵌套的 class 定义。

这是我目前尝试过的方法。

能否有另一种快速简单的方法来处理此更改。

我不知道有什么比写一个小脚本更好的方法了。我认为这些变化足够小,您可以通过一些不错的启发式方法逃脱,并且不需要 ast.

的全部功能

但是,如果您有这么多重复的代码,我会从您的代码中完全删除 类。您可以用代码生成器替换它们或为这些 类 编写工厂函数。这将 future-proof 您的代码进行任何更改。

这样的工厂可能是这样的:

class HasStringInstances(type):
    def __instancecheck__(cls, instance):
        return instance in cls.__slots__

def create_special_class(*slots):
    class SpecialClass(object, metaclass=HasStringInstances):
        __slots__ = slots

        def __init__(self):
            for slot in self.__slots__:
                 # assign name as value
                 setattr(self, slot, slot)

    return SpecialClass

Sample = create_special_class('both', 'advertise')