Python:私有内部枚举中的静态方法class

Python: Static method inside private inner Enum class

我在实现名为 class 的内部私有枚举 class 时遇到问题: "LineCode" 在 class 命名的解析器中。

LineCode: Private Enum class 定义了 6 种一般可能的代码行。我使用枚举实例化来发送正则表达式模式并在构造函数 __init__ 中编译它,然后将正则表达式匹配器作为 class 变量保存。

Parser: 解析一种编程语言,与什么语言无关。解析器正在使用 LineCode 来识别行并进行相应处理。

问题: 我无法从静态方法访问 __LineCode 的枚举成员。 我希望在 __LineCode、"matchLineCode(line)" 中有一个静态方法,它从解析器接收一个字符串,然后按以下逻辑遍历 Enum 成员:

这看起来并不简单,我无法访问枚举成员来执行此操作。

尝试: 我尝试使用以下方法遍历枚举:

  1. __LineCode.__members__.values()
  2. Parser.__lineCode.__members__.values()

都失败了,因为它找不到 __lineCode。

理想情况下: LineCode class 必须是私有的,并且对导入解析器的任何其他 class 不可见。解析器必须使用 LineCode class 提供给 return Enum 的静态方法。我愿意接受解决此问题的任何解决方案或模仿此行为的解决方案。

为了提高可读性,我省略了一些不相关的Parser方法。 代码:

class Parser:
    class __LineCode(Enum):
        STATEMENT = ("^\s*(.*);\s*$")
        CODE_BLOCK = ("^\s*(.*)\s*\{\s*$")
        CODE_BLOCK_END = ("^\s*(.*)\s*\}\s*$")
        COMMENT_LINE = ("^\s*//\s*(.*)$")
        COMMENT_BLOCK = ("^\s*(?:/\*\*)\s*(.*)\s*$")
        COMMENT_BLOCK_END = ("^\s*(.*)\s*(?:\*/)\s*$")
        BLANK_LINE = ("^\s*$")

        def __init__(self, pattern):
            self.__matcher = re.compile(pattern)

        @property
        def matches(self, line):
            return self.__matcher.match(line)

        @property
        def lastMatch(self):
            try:
                return self.__matcher.groups(1)
            except:
                return None

        @staticmethod
        def matchLineCode(line):
            for lineType in **???**:
                if lineType.matches(line):
                    return lineType
            return None

    def __init__(self, source=None):
        self.__hasNext = False
        self.__instream = None
        if source:
            self.__instream = open(source)

    def advance(self):
        self.__hasNext = False
        while not self.__hasNext:
            line = self.__instream.readline()
            if line == "":  # If EOF
                self.__closeFile()
                return
            lineCode = self.__LineCode.matchLineCode(line)
            if lineCode is self.__LineCode.STATEMENT:
                pass
            elif lineCode is self.__LineCode.CODE_BLOCK:
                pass
            elif lineCode is self.__LineCode.CODE_BLOCK_END:
                pass
            elif lineCode is self.__LineCode.COMMENT_LINE:
                pass
            elif lineCode is self.__LineCode.COMMENT_BLOCK:
                pass
            elif lineCode is self.__LineCode.COMMENT_BLOCK:
                pass
            elif lineCode is self.__LineCode.BLANK_LINE:
                pass
            else:
                pass  # TODO Invalid file.

我已经在Java中实现了,我想在Python中重构同样的东西:

private enum LineCode {
        STATEMENT("^(.*)" + Syntax.EOL + "\s*$"), // statement line
        CODE_BLOCK("^(.*)" + Syntax.CODE_BLOCK + "\s*$"), // code block open line
        CODE_BLOCK_END("^\s*" + Syntax.CODE_BLOCK_END + "\s*$"), // code block close line
        COMMENT_LINE("^\s*" + Syntax.COMMENT + "(.*+)$"), // comment line
        BLANK_LINE("\s*+$"); // blank line

        private final static int CONTENT_GROUP = 1;

        private Pattern pattern;
        private Matcher matcher;

        private LineCode(String regex) {
            pattern = Pattern.compile(regex);
        }

        boolean matches(String line) {
            matcher = pattern.matcher(line);
            return matcher.matches();
        }

        String lastMatch() {
            try {
                return matcher.group(CONTENT_GROUP);
            } catch (IndexOutOfBoundsException e) {
                return matcher.group();
            }
        }
    static LineCode matchLineCode(String line) throws    UnparsableLineException {
        for (LineCode lineType : LineCode.values())
            if (lineType.matches(line)) return lineType;
        throw new UnparsableLineException(line);
    }

谢谢。

您可以将 staticmethod 更改为 classmethod,这样传递给 matchLineCode 的第一个参数将是 __lineCode class,您将能够迭代它


编辑

我决定添加更详细的解释,说明为什么使用 @staticmethod 装饰器的 matchLineCode 无法看到 __lineCode class。首先,我建议您阅读 SO 上发布的一些关于 difference between static and class methods 的问题。主要区别在于 classmethod 知道定义方法的 Class,而 staticmethod 不知道。这并不意味着您无法从 staticmethod 中看到 __lineCode class,它只是意味着您将需要做更多的工作才能做到这一点。

您组织代码的方式,class __lineCode 是 class Parser 的 class 属性。在 python 中,方法总是 public,没有私有或受保护的 class 成员,如在 Java 中。但是,class 属性名称(或实例的属性名称)开头的双下划线表示该名称将为 mangled with the class name。这意味着在 class Parser 之外定义的任何函数都可以访问 __lineCode class 作为

Parser._Parser__lineCode

这意味着使用 @staticmethod 装饰器,您可以通过

迭代 __lineCode
@staticmethod
def matchLineCode(line):
    for lineType in Parser._Parser__lineCode:
        if lineType.matches(line):
            return lineType
    return None

但是,在我看来,使用 @classmethod 装饰器让函数知道 __lineCode class.