C++中,给定一个类层次结构,最派生类的Cor调用其基类Cor,然后在实例化派生的部分之前初始化对象的基部。在Python中,我想了解在我有这样一个需求的情况下发生了什么,即派生子类一个给定的基类,该基类在它的__init__
方法中接受一个可调用的,然后它会调用该方法。可调用的特性是我在派生类的__init__
中传递的一些参数,这也是我定义可调用函数的地方。然后,我的想法是在定义了__call__
操作符之后,将派生类本身传递给它的基类
class Derived(Base):
def __init__(self, a, b):
def _process(c, d):
do_something with a and b
self.__class__.__call__ = _process
super(Derived, self).__init__(self)
__init__
方法中的第一条指令,还是可以按我的方式进行调用李>
很明显,您在代码中看到的-
Base.__init__()
只有在您显式地请求它时才被调用(使用super()
调用)。如果Base
也有父级,并且链中的每个人都使用super()
调用,则将根据mro调用父级初始值设定项基本上,Python是一种“运行时语言”——除了字节码编译阶段,所有的事情都发生在运行时——所以很少有“黑魔法”在发生(实际上,它的大部分内容都是文档化的,并且完全公开给那些想深入研究或进行元编程的人)
在您认为适合具体用例的地方调用父级的方法—您只需注意在定义实例属性之前不要使用实例属性(直接或不太明显—通过依赖于这些属性的方法调用间接)
如果您不需要向后兼容,请使用
super()
而不带参数-除非您想显式跳过MRO中的某个类,但是很可能您的设计中有一些值得商榷的地方(但是,有时我们不能仅仅为了避免一个非常特殊的情况而重写整个代码库,所以只要你明白自己在做什么和为什么,那也没关系现在谈谈你的核心问题:
self.__class__.__call__
是类属性,由类的所有实例共享。这意味着您必须确保您只使用了类的一个实例(这似乎不是这里的目标),或者准备好获得完全随机的结果,因为每个新实例都将用它自己的版本覆盖self.__class__.__call__
如果您想让每个实例的
__call__
方法调用它自己的process()
版本,那么有一个更简单的解决方案-只需将_process
作为实例属性并从__call__
调用它:或者更简单:
编辑:
如果您的示例片段更接近您的实际用例,这会更好
这是个好问题。。。实际上,Python方法并不是你想象的那样。使用
def
语句在class
语句体中定义的仍然是普通函数,如您自己所见:“方法”仅在属性查找解析为恰好是函数的类属性时才实例化:
(如果你想知道这是怎么发生的,那就是documented here)
实际上,它们只是围绕函数、实例和类(或classmethods的函数和类)的精简包装器,将调用委托给底层函数,将实例(或类)作为第一个参数注入。在CS术语中,Python方法是函数对实例(或类)的部分应用
正如我前面提到的,Python是一种运行时语言,
def
和class
都是可执行语句。因此,在定义Derived
类时,创建Base
类对象的class
语句已经执行(否则Base
根本不存在),所有的class
语句块都首先执行(以定义函数和其他类属性)因此,“当您调用
super().__init()__
时,__call__
函数Base
已经实例化(假设它是在class
语句中为Base
定义的,但这是目前为止最常见的情况)相关问题 更多 >
编程相关推荐