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

时间:2016-12-28 09:53:55

标签: python enums static-methods

我在实现内部私有枚举类时遇到了问题:" LineCode"在一个名为Parser的类中。

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

Parser:解析一种编程语言,与语言无关。解析器使用LineCode来识别行并相应地继续。

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

  • 如果找到匹配:返回枚举
  • 如果没有剩下的枚举:返回无

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

尝试:我尝试使用以下方法迭代枚举:

  1. __线路码.__成员__。值()
  2. 分析器.__线路码.__成员__。值()
  3. 两者都失败了,因为它无法找到__lineCode。

    理想情况下: LineCode类必须是私有的,并且对于导入Parser的任何其他类都不可见。解析器必须使用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.
    

    我已经用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);
        }
    

    感谢。

1 个答案:

答案 0 :(得分:4)

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

修改

我已决定添加更详细的说明,说明使用matchLineCode装饰器的@staticmethod无法看到__lineCode类的原因。首先,我建议您阅读一些关于difference between static and class methods的SO上发布的问题。主要区别在于classmethod知道定义方法的类,而staticmethod则不知道。这并不意味着您无法看到__lineCode中的staticmethod课程,只是意味着您还需要做更多的工作。

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

访问__lineCode
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类是可以理解的。