我有一个有许多孩子的Parent
课程:
class Parent(Object):
def function(self):
do_something()
class Child1(Parent):
def function(self):
super(Child1, self).function()
do_something_else_1()
class Child2(Parent):
def function(self):
do_something_else_2()
等等。
几乎所有孩子都应该调用do_something()
。如果有人在没有进行super
调用的情况下编写子课程,我会发出警告,例如Child2
。我该怎么做?
答案 0 :(得分:4)
您可以实现类似的一种方法是为子类提供一个“强制”的界面。一个子类的编写器来获取基本行为,甚至不必调用super:
class Parent(object):
def _extra_functions(self):
# Override me in derived classes!
pass
def function(self):
# Don't override me
do_something()
self.extra_functions()
class Child1(Parent):
def _extra_functions(self):
do_something_else_1()
class Child2(Parent):
def _extra_functions(self):
do_something_else_2()
这仍然依赖于子类的编写者以你想要的方式行事。无论你怎么努力,任何解决方案都可以解决问题。将永远能够由一个聪明的开发人员解决,所以如果你绝对必须有这个,那么python可能不是正确的语言。但是,这个(或其他答案)非常清楚开发人员如何假设扩展此类。
答案 1 :(得分:3)
另一种不那么全面的方法你可以通过使用一个功能并检查其内部的装饰器。这个装饰者可以做的是检查func_code.co_names
(Py3中的func.__code__.co_names
)以查看super
以及函数名func.func_name
(Py3中的func.__name__
)是否为本:
def require_super(func):
f_name = func.func_name
other_names = func.func_code.co_names
if not all(val in other_names for val in [f_name, 'super']):
warnings.warn("Super must be defined on function: " + f_name)
return func
f_name
当然是定义的函数名称。
all(val in other_names for val in [f_name, 'super'])
将浏览other_names
中的姓名并检查f_name
和super
是否作为条目存在。 如果不 ,它会发出警告然后返回该函数,如果是这种情况,则返回该函数。
当用户定义一个类并且没有提供超级调用时,将在执行类主体期间引发warning
:
class foo(Parent):
@require_super
def function(self, arg):
s = "No super"
这会返回以下形式的警告:
UserWarning: Super must be defined on function: function
您可以记录/忽略您可以使用它做任何事情。
这绝对看起来很脆弱,而且很可能。您可以更改装饰器require_super
以进行更智能的检查。请记住,关于(类)函数的所有内容都存在于底层的code
对象中,然后破解它并且您将能够执行任何您想要的任何操作。
在幕后执行此操作的方法是使用元类。通过这样做,您可以获得使用type(cls) = mymetaclass
定义的任何类以及子类化原始类的任何其他类的快照。我们已经定义的函数require_super
现在可以成为元类的staticmethod
(不是必需但为什么不是),我们将其称为每次定义新类时检查函数对象。
让我们首先定义我们的元类:
class requireMeta(type):
_requiredFunc = 'function'
def __new__(cls, *args):
# base classes, dictionary of functions
bases, funcs = args[1], args[2]
# skip the check for the base class
# which inherits from object
if not bases[0].__name__ == 'object':
try:
# run requireSuper for the function 'function'
cls.requireSuper(funcs[cls._requiredFunc])
except KeyError:
# if it doesn't exist, complain.
warnings.warn("Function: {} must be defined!".format(cls._requiredFunc))
return super(requireMeta, cls).__new__(cls, *args)
@staticmethod
def requireSuper(func):
"""
Functionality is the same as described already.
"""
f_name = func.func_name
other_names = func.func_code.co_names
if not all(val in other_names for val in [f_name, 'super']):
warnings.warn("Super must be defined on function: " + f_name)
return func
因此,当创建__new__
类时,我们的元类在这里做的是:它接受它的基础和它定义的函数,检查基数是否不包含object
(这里有差异)对于Py3的情况,意味着定义的类是一个子类,并尝试将名为'function'
的函数传递给require_super
。如果该功能不存在则会发出警告;如果它执行require_super
提供的相同功能。
现在,此处所需的其他更改是将Parent
的类型指定为requireMeta
,这是通过__metaclass__
属性完成的:
class Parent(object):
__metaclass__ = requireMeta
def function(self):
print("Doing Something")
在Py3中,与class Parent(metaclass = requireMeta)
完成同样的事情,仅此而已:-)。
当Python发现这个类定义时,它最终将使用适当的参数发出调用requireMeta.__new__
。好的是,此调用是针对Parent
以及Parent
的任何子类进行的,因此您的子类Child1
和Child2
可以保持原样并且在调用元类__new__
时将进行检查:
class Child1(Parent):
def function(self):
super(Child1, self).function()
do_something_else_1()
执行顺利,没有发出警告。另一方面,这个定义:
class Child2(Parent):
def function(self):
do_something_else_2()
将打印:
UserWarning: Super must be defined on function: function
虽然未定义function
的定义:
class Child3(Parent):
pass
将打印:
UserWarning: Function: function must be overriden!