1

我必须将遗留代码(~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'

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

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

这是我到目前为止所尝试的。

  • 2to3不认为这是一个问题,因此不会改变它。
  • 一种可能的方法是使用ast模块来修改内存中的解析树,然后用它unparse来写回修改后的代码。但这并不简单。
  • 如果没有其他工作,我会考虑编写一个简单的 Shell/Python 脚本,它将读取源文件、进行更改并将其写回。

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

4

1 回答 1

2

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

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

这样的工厂可能如下所示:

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')
于 2017-02-01T11:23:19.220 回答