【发布时间】:2020-03-18 14:51:15
【问题描述】:
我有一个超类和一个子类,它们需要根据正则表达式以不同方式处理它们的初始化。请参阅下面的工作示例。
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时,都会重新编译正则表达式。 - 不能从
Sample中的其他类方法调用match函数(例如,我可能希望能够在初始化@987654326 之前检查文件是否具有有效的名称 - 相对于RE@来自它)。
简单地说,我想要这样的东西:
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参数?
【问题讨论】:
-
你总是可以使用元类来做到这一点,但我不确定这是一个解决方案还是另一个问题...... ;-)
-
您的方法将失败,因为
RE = ...到match =的行仅在模块加载时评估一次。因此更改RE = ...和STRICT_MATCHING = ...没有没有效果。 -
您可以简单地自己提供
RE = re.compile(r'...'),而不是让班级为您调用re.compile。 -
@thebjorn
__init_subclass__的引入正是为了避免这里需要一个成熟的元类 :) -
re模块会缓存最近编译的模式,因此一遍又一遍地重复编译相同的几个模式可能不会受到惩罚(如果它们是仍在缓存中)。
标签: python python-3.x inheritance class-variables