Python - 覆盖类变量的初始化

标签 python python-3.x inheritance class-variables

我有一个父类(super class)和一个子类,它们需要基于正则表达式以不同方式处理它们的初始化。请参阅下面的工作示例。

import os
import re


class Sample:
    RE = r'(?P<id>\d+)'
    STRICT_MATCHING = False

    def __init__(self, f):
        self.file = f
        self.basename = os.path.basename(os.path.splitext(self.file)[0])

        re_ = re.compile(self.RE)
        match = re_.fullmatch if self.STRICT_MATCHING else re_.match
        self.__dict__.update(match(self.basename).groupdict())


class DetailedSample(Sample):
    RE = r'(?P<id>\d+)_(?P<dir>[lr])_(?P<n>\d+)'
    STRICT_MATCHING = True


s1 = Sample("/asdf/2.jpg")
print(s1.id)
s2 = DetailedSample("/asdfadsf/2_l_2.jpg")
print(s2.id, s2.dir, s2.n)

此代码有效,但有两个缺点:
  • 每次新的 Sample 都会重新编译正则表达式被初始化。
  • match Sample 中的其他类方法不能调用函数(例如,我可能希望能够检查一个文件是否有一个有效的名称 - 相对于 RE - 在从它初始化 Sample 之前)。

  • 简单地说,我想要这样的东西:
    class Sample:
        RE = r'(?P<id>\d+)'
        STRICT_MATCHING = False
        re_ = re.compile(RE)  #
        match = re_.fullmatch if STRICT_MATCHING else re_.match  #
    
        def __init__(self, f):
            self.file = f
            self.basename = os.path.basename(os.path.splitext(self.file)[0])
    
            self.__dict__.update(self.match(self.basename).groupdict())
    
        @classmethod
        def valid(cls, f):
            basename, ext = os.path.splitext(os.path.basename(f))
            return cls.match(basename) and ext.lower() in ('.jpg', '.jpeg', '.png')
    
    
    class DetailedSample(Sample):
        RE = r'(?P<id>\d+)_(?P<dir>[lr])_(?P<n>\d+)'
        STRICT_MATCHING = True
    

    然而,这显然不适用于子类,因为标有 # 的两行重新定义 RE 后不会执行和 STRICT_MATCHING在子类中。

    有没有一种方法可以:
  • 保留第一种方法的功能(即基于正则表达式的初始化);
  • 每个子类只编译一次正则表达式并定义一次匹配方法;
  • 允许从类方法中调用匹配方法;
  • 只需要重新定义正则表达式字符串和STRICT_MATCHING子类中的参数?
  • 最佳答案

    您可以使用 __init_subclass__确保每个子类都做适当的工作。这将在您的公共(public)基类继承的私有(private)基类中定义。

    import os
    import re
    
    
    class _BaseSample:
        RE = r'(?P<id>\d+)'
        STRICT_MATCHING = False
    
        def __init_subclass__(cls, **kwargs):
            super().__init_subclass__(**kwargs)
            cls._re = re.compile(cls.RE)
            cls.match = cls._re.fullmatch if cls.STRICT_MATCHING else cls._re.match
    
    
    class Sample(_BaseSample):
        def __init__(self, f):
            self.file = f
            self.basename = os.path.basename(os.path.splitext(self.file)[0]
            self.__dict__.update(self.match(self.basename).groupdict())
    
    
    class DetailedSample(Sample):
        RE = r'(?P<id>\d+)_(?P<dir>[lr])_(?P<n>\d+)'
        STRICT_MATCHING = True
    
    
    s1 = Sample("/asdf/2.jpg")
    print(s1.id)
    s2 = DetailedSample("/asdfadsf/2_l_2.jpg")
    print(s2.id, s2.dir, s2.n)
    

    除非您以后需要直接访问已编译的正则表达式,否则 _re可以是 _BaseSample.__init_subclass__ 的局部变量而不是每个类的类属性。

    请注意 __init_subclass__也可以接受额外的关键字参数,作为关键字参数提供给 class声明本身。我不认为这样做有什么特别的好处。这只是你想提供什么接口(interface)来设置RE的问题。和 STRICT_MATCHING .见 Customizing Class Creation详情。

    关于Python - 覆盖类变量的初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58995817/

    相关文章:

    python - Statsmodels - 负二项式不收敛,而 GLM 收敛

    Python - 循环读取RFID

    python-3.x - Pandas 通过取列之间的平均值来合并两个数据帧

    c++ - 将嵌套的基模板类实例声明为派生类的 friend

    oop - 表示派生类上的 "container"派生自基类容器的设计模式

    python - 如何从脚本中找到 Python 运行脚本的目录?

    python - 如何用 Python 中的其他多项式替换多项式中的 x?

    python - 我正在尝试使用 pandas 和 sqlalchemy 将数据加载到 redshift 中

    python - 需要 SqlAlchemy 单表继承的经典映射器示例

    python - 读取二进制文件时如何解决 EOF 错误