使用 __init_subclass__ 修补抽象方法,同时保留 abc 检查
Use __init_subclass__ to patch abstract methods while preserving the abc check
我想为 abc 的所有子类包装一个 abstractmethod
。我尝试通过如下实施 __init_subclass__
来做到这一点:
import abc
class Base(abc.ABC):
@abc.abstractmethod
def foo(self) -> str:
pass
def __init_subclass__(cls):
super().__init_subclass__()
orig_foo = cls.foo
cls.foo = lambda s: orig_foo(s) + 'def'
class Derived(Base):
def foo(self):
return 'abc'
这有效,如果我做类似的事情:
derived = Derived()
derived.foo() # -> 'abcdef'
这是预期的。不幸的是,我注意到这种方法不会调用 abc 检查,所以如果我忘记在 Derived
:
上实现 foo
class Derived(Base):
pass
我还能创造它:
derived = Derived() # This works
derived.foo() # -> TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
有没有办法进行上述包装,但又不破坏 abc.abstractmethod
检查?
只有当 cls.foo
不同于Base.foo
(即已被覆盖)。
这会产生以下 Base
实现:
class Base(abc.ABC):
@abc.abstractmethod
def foo(self) -> str:
pass
def __init_subclass__(cls):
super().__init_subclass__()
orig_foo = cls.foo
if orig_foo != Base.foo: # Already overridden.
cls.foo = lambda s: orig_foo(s) + 'def'
我认为更好的技术是声明一个单独的 non-abstract 使用抽象方法的方法。
导入 abc
class Base(abc.ABC):
@abc.abstractmethod
def foo_body(self) -> str:
pass
def foo(self) -> str:
return self.foo_body() + 'def'
class Derived(Base):
def foo_body(self):
return 'abc'
具体的子类只负责重写foo_body
; Base.foo
本身就不用动了
我想为 abc 的所有子类包装一个 abstractmethod
。我尝试通过如下实施 __init_subclass__
来做到这一点:
import abc
class Base(abc.ABC):
@abc.abstractmethod
def foo(self) -> str:
pass
def __init_subclass__(cls):
super().__init_subclass__()
orig_foo = cls.foo
cls.foo = lambda s: orig_foo(s) + 'def'
class Derived(Base):
def foo(self):
return 'abc'
这有效,如果我做类似的事情:
derived = Derived()
derived.foo() # -> 'abcdef'
这是预期的。不幸的是,我注意到这种方法不会调用 abc 检查,所以如果我忘记在 Derived
:
foo
class Derived(Base):
pass
我还能创造它:
derived = Derived() # This works
derived.foo() # -> TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
有没有办法进行上述包装,但又不破坏 abc.abstractmethod
检查?
只有当 cls.foo
不同于Base.foo
(即已被覆盖)。
这会产生以下 Base
实现:
class Base(abc.ABC):
@abc.abstractmethod
def foo(self) -> str:
pass
def __init_subclass__(cls):
super().__init_subclass__()
orig_foo = cls.foo
if orig_foo != Base.foo: # Already overridden.
cls.foo = lambda s: orig_foo(s) + 'def'
我认为更好的技术是声明一个单独的 non-abstract 使用抽象方法的方法。
导入 abc
class Base(abc.ABC):
@abc.abstractmethod
def foo_body(self) -> str:
pass
def foo(self) -> str:
return self.foo_body() + 'def'
class Derived(Base):
def foo_body(self):
return 'abc'
具体的子类只负责重写foo_body
; Base.foo
本身就不用动了