6

我有一个可以重写 Python 模块的脚本,以便将所有出现func(a)func2(a is None). 我现在也想支持func(a, msg)成为func2(a is None, msg),但我找不到可以做到这一点的模式。以下显示了我的尝试:

from lib2to3 import refactor, fixer_base
from textwrap import dedent

PATTERN_ONE_ARG = """power< 'func' trailer< '(' arglist< obj1=any > ')' > >"""

PATTERN_ONE_OR_TWO_ARGS = """power< 'func' trailer< '(' arglist< obj1=any [',' obj2=any] > ')' > >"""


class TestFixer(fixer_base.BaseFix):
    def __init__(self, options, fixer_log):
        # self.PATTERN = PATTERN_ONE_ARG
        self.PATTERN = PATTERN_ONE_OR_TWO_ARGS

        super().__init__(options, fixer_log)

    def transform(self, node, results):
        print("found it")
        return node


class TestRefactoringTool(refactor.MultiprocessRefactoringTool):
    def get_fixers(self):
        fixer = TestFixer(self.options, self.fixer_log)
        return [fixer], []


def test():
    test_script = """
        log.print("hi")
        func(a, "12345")
        func(a, msg="12345")
        func(a)
        """
    refac.refactor_string(dedent(test_script), 'script')


flags = dict(print_function=True)
refac = TestRefactoringTool([], flags)
test()

对于functest_script字符串中找到的每一个,我应该看到一个“找到它”,所以总共有 3 个,但我只看到打印了 2 个,这意味着func(a)模式匹配器没有找到。我将模式基于 中可用的修复程序lib2to3.fixes,但我一定错过了一个微妙之处。任何人都知道谁来修复 PATTERN_ONE_OR_TWO_ARGS 以便找到所有 3 个功能?

我知道我可以创建一个单独的修复程序实例,但是使用该模式可以让我免于编写大量代码(我有几十个这样的修复程序,总共将是 24 个!)。

4

1 回答 1

3

找到了:

PATTERN_ONE_OR_TWO_ARGS = """
    power< 'func' trailer< '('
        ( not(arglist | argument<any '=' any>) obj1=any
        | arglist< obj1=any ',' obj2=any > )
    ')' > >
    """

如果 transform() 是:

def transform(self, node, results):
    if 'obj2' in results:
        print("found 2", results['obj1'], results['obj2'])
    else:
        print("found 1", results['obj1'])
    return node

那么对于

test_script = """
    log.print("hi")
    func(a, "12345")
    func(a, msg="12345")
    func(a)
    func(k=a)
    """

输出是

found 2 a  "12345"
found 2 a  msg="12345"
found 1 a

我还发现http://python3porting.com/fixers.html#fixers-chapter表明我可以重写 match() 方法而不是使用模式。四种感兴趣的模式是:

PATTERN_ONE_ARG_OR_KWARG   = """power< 'func' trailer< '(' not(arglist) obj1=any                         ')' > >"""
PATTERN_ONE_ARG            = """power< 'func' trailer< '(' not(arglist | argument<any '=' any>) obj1=any ')' > >"""
PATTERN_ONE_KWARG          = """power< 'func' trailer< '(' obj1=argument< any '=' any >                  ')' > >"""
PATTERN_TWO_ARGS_OR_KWARGS = """power< 'func' trailer< '(' arglist< obj1=any ',' obj2=any >              ')' > >"""
于 2016-02-08T05:02:58.773 回答