Python:私有内部Enum类中的静态方法

Ben*_*Ben 3 python enums static-methods

我在实现名为Parser的类中实现内部私有枚举类:“ LineCode”时遇到了麻烦。

LineCode:私有Enum类,它定义6种通用可能的代码行类型。我使用Enum实例化发送正则表达式模式,并在构造函数__init__中对其进行编译,然后将正则表达式匹配器作为类变量保存。

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

问题:我无法从静态方法访问__LineCode的枚举成员。我希望在__LineCode中有一个static方法“ matchLineCode(line)”,该方法从解析器接收一个字符串,然后按以下逻辑对Enum成员进行迭代:

  • 如果找到匹配项:返回枚举
  • 如果没有更多的枚举:不返回

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

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

  1. __LineCode .__ members __。values()
  2. 解析器.__ lineCode .__成员__。values()

两者均失败,因为找不到__lineCode。

理想情况下: LineCode类必须是私有的,并且对于导入解析器的任何其他类都不可见。解析器必须使用LineCode类提供的静态方法来返回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.
Run Code Online (Sandbox Code Playgroud)

我已经用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);
    }
Run Code Online (Sandbox Code Playgroud)

谢谢。

luc*_*paz 5

您可以将更staticmethod改为classmethod,这样传递给第一个参数的matchLineCode将是__lineCode该类,并且可以对其进行迭代


编辑

我决定添加一个更详细的解释,说明为什么matchLineCode使用@staticmethod装饰器无法看到__lineCode该类。首先,我建议您阅读SO上发布的一些问题,这些问题谈论静态方法和类方法之间区别。主要区别在于classmethod可以知道在哪里定义了方法,而staticmethod不是。这并不意味着您无法从中看到__lineCode该类staticmethod,仅意味着您将需要做更多的工作。

__lineCode是组织代码的方式,它是class 的类属性Parser。在python中,方法始终是公共的,没有Java中的私有或受保护的类成员。但是,类属性名称(或实例属性名称)开头的双下划线表示该名称将与类名称混为一谈。这意味着在类外部定义的任何函数Parser都可以按以下方式访问__lineCode该类:

Parser._Parser__lineCode
Run Code Online (Sandbox Code Playgroud)

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

@staticmethod
def matchLineCode(line):
    for lineType in Parser._Parser__lineCode:
        if lineType.matches(line):
            return lineType
    return None
Run Code Online (Sandbox Code Playgroud)

但是,使用@classmethod修饰符使函数知道__lineCode该类的可读性更高,并且在我看来是可以理解的。