如何处理父类和子类的情况
问题描述:
我有成百上千个.py文件,这些文件定义了pydantic的模式。突然之间,我需要把空字符串当作None来处理。我希望在所有文件中做的改动尽量少。
我采取的做法:
我创建了一个继承类,像这样:
class ConstrainedStr(str):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v: str, field: Field) -> Optional[str]:
v = v.strip()
if v == "":
return None
return v
然后,在所有的.py文件中,我只添加了一条导入语句:
from package.module import ConstrainedStr as str
幸运的是,第一次尝试就成功了。但我遇到了一个问题,我有一个函数:
用户文件:
from package.module import ConstrainedStr as str
def validate(cls, value:str): //sample value 'asd'
if isinstance(value, str):
validation_rule()
在这里,这个条件判断失败了。
问题
- 我怎么才能避免大改动来实现这个?有没有办法?
- 为什么那个isinstance检查失败了?ConstrainedStr也是一个str,对吧?我的理解错了吗?
当我进一步深入研究时,只是为了理解第二个问题的行为,我发现了以下内容。
type(ConstrainedStr)
返回 type<class>
。
`type('123')`
返回 type<str>
但是当我检查builtins
包时,发现str
也是一个类。但type函数返回str
的类型是str
,而对于ConstrainedStr
却返回class
。所以,我的第二个问题就出现了。
另一个例子:
class A(int):
pass
isinstance(2, A)
# False
这就是我的第二个问题。
1 个回答
3
当一个子类的实例被创建时,它自动也成为了父类的实例,但反过来就不一定成立。这就像每只猫都是哺乳动物,但并不是每个哺乳动物都是猫。
同样,因为 ConstrainedStr
是 str
的子类,所以 ConstrainedStr
的实例自动也是 str
的实例。但是,反过来就不成立,比如 'asd'
这个 str
的实例就不能自动被认为是 ConstrainedStr
的实例。
如果你想让反向的实例检查也成立,可以通过在元类中定义 __instancecheck__
来定制 isinstance
的行为。同时,通过定义 __subclasscheck__
来定制 issubclass
,以保持这些关系的一致性。
为了实现你想要的行为,你自定义的 __instancecheck__
应该在给定的实例是任何父类的实例时返回 True
:
class SubstitutableMeta(type):
def __instancecheck__(cls, instance):
return any(isinstance(instance, base) for base in cls.__bases__)
def __subclasscheck__(cls, subclass):
return any(issubclass(subclass, base) for base in cls.__bases__)
class ConstrainedStr(str, metaclass=SubstitutableMeta):
pass
print(isinstance('asd', ConstrainedStr)) # outputs True