事实上,你不应该依赖inspect.getsourcelines
对于任何应该在严肃的环境中使用的代码(即实验领域之外,或处理源代码本身的工具)
简单明了is
运算符足以检查给定类中的方法是否与基类中的方法相同。 (在 Python 3 中。Python 2 用户必须注意将方法检索为unbound methods
而不是原始函数)
除此之外,您还需要经过几次不必要的轮转才能到达基类本身 -很少有记录并且很少使用特殊变量__class__ https://docs.python.org/3/reference/datamodel.html#creating-the-class-object可以帮助您:它是对编写它的类主体的自动引用(不要误认为self.__class__
这是对子类的引用)。
从文档中:
此类对象将以零参数形式引用super(). __class__
是编译器创建的隐式闭包引用,如果类体中的任何方法引用其中之一__class__
or super
. 这允许零参数形式super()
正确识别正在定义的类基于词法作用域,而用于进行当前调用的类或实例是根据传递给该方法的第一个参数来识别的。
因此,在保持主要方法的同时,整个事情可以变得非常简单:
def __init_subclass__(cls):
required_methods = ['on_connected', 'on_disconnected', 'on_message']
for f in required_methods:
if getattr(cls, f) is getattr(__class__, f):
raise NotImplementedError(...)
如果您有一个复杂的层次结构,并且父类具有其他强制方法,这些方法的子类必须实现这些方法 - 因此,无法在required_methods
,您仍然可以使用abstractmethod
装饰器来自abc
,不使用ABCMeta
元类。装饰器所做的就是在元类上检查的方法上创建一个属性。只需在 a 中进行相同的检查__init_subclass__
method:
from abc import abstractmethod
class Base:
def __init_subclass__(cls, **kw):
super().__init_subclass__(**kw)
for attr_name in dir(cls):
method = getattr(cls, attr_name)
if (getattr(method, '__isabstractmethod__', False) and
not attr_name in cls.__dict__):
# The second condition above allows
# abstractmethods to exist in the class where
# they are defined, but not on further subclasses
raise NotImplementedError(...)
class NetworkMixin(Base):
@abstractmethod
def on_connect(self):
pass
class FileMixin(Base):
@abstractmethod
def on_close(self):
pass
class MyFileNetworkThing(NetworkMixin, FileMixin):
# if any of the two abstract methods is not
# implemented, Base.__init_subclass__ will fail
请记住,这只是检查类中出现的方法”dir
。但定制__dir__
很少使用,因此它是可靠的 - 只需注意记录即可。