Python多继承与包装类相关技术疑问咨询
第一种继承模式与疑问
先看你给出的第一种模式代码:
from api.client import Client from api.wrapper import Wrapper class TestClient(Client): def __init__(self, wrapper): Client.__init__(self, wrapper) class TestWrapper(Wrapper): def __init__(self): Wrapper.__init__(self) def updateMktDepth(self, reqId: TickerId, position: int, operation: int, side: int, price: float, size: int): super().updateMktDepth(reqId, position, operation, side, price, size) print("UpdateMarketDepth", "ReqId:", reqId, "Position:", position, "Operation:", operation, "Side:", side, "Price:", price, "Size:", size) def updateMktDepthL2(self, reqId: TickerId, position: int, marketMaker: str, operation: int, side: int, price: float, size: int, isSmartDepth: bool): super().updateMktDepthL2(reqId, position, marketMaker, operation, side, price, size, isSmartDepth) print("UpdateMarketDepthL2", "ReqId:", reqId, "Position:", position, "MarketMaker:", marketMaker, "Operation:", operation, "Side:", side, "Price:", price, "Size:", size, "isSmartDepth:", isSmartDepth) def main(): wrapper = TestWrapper() client = TestClient(wrapper) client.connect('127.0.0.1', 3847, 100) print('Connection successful') client.disconnect()
疑问解答:实例化TestClient传wrapper参数是否和*args/**kwargs相关?
完全无关,你可能看错了代码——TestClient的__init__方法是显式声明了wrapper参数的:def __init__(self, wrapper):。其中self是Python类方法的默认第一个参数(代表当前实例),第二个参数就是wrapper,所以实例化TestClient(wrapper)是完全匹配参数定义的正常传参操作。
第二种多继承模式与疑问
再看第二种模式的代码(包含Client类定义):
from api.client import Client from api.wrapper import Wrapper class TestApp(Client, Wrapper): def __init__(self): Client.__init__(self, self) def updateMktDepth(self, reqId: TickerId, position: int, operation: int, side: int, price: float, size: int): super.updateMktDepth(reqId, position, operation, side, price, size) print("UpdateMarketDepth", "ReqId:", reqId, "Position:", position, "Operation:", operation, "Side:", side, "Price:", price, "Size:", size) def updateMktDepthL2(self, reqId: TickerId, position: int, marketMaker: str, operation: int, side: int, price: float, size: int, isSmartDepth: bool): super.updateMktDepthL2(reqId, position, operation, side, price, size) print("UpdateMarketDepthL2", "ReqId:", reqId, "Position:", position, "MarketMaker:", marketMaker, "Operation:", operation, "Side:", side, "Price:", price, "Size:", size, "isSmartDepth:", isSmartDepth) class Client(object): (DISCONNECTED, CONNECTING, CONNECTED, REDIRECT) = range(4) def __init__(self, wrapper): self.msg_queue = queue.Queue() self.wrapper = wrapper self.decoder = None self.reset()
疑问1:多继承下super如何确定方法位置?
Python多继承靠**方法解析顺序(MRO)**来决定查找方法的顺序,你可以通过TestApp.__mro__或者TestApp.mro()打印出具体的顺序列表。当调用super().xxx()时,会严格按照MRO列表的顺序,从当前类的下一个类开始依次查找,找到第一个包含目标方法的类就调用它。
比如TestApp继承了Client和Wrapper,假设MRO是[TestApp, Client, Wrapper, object],如果updateMktDepth只在Wrapper中存在,那super就会跳过Client,直接找到Wrapper的该方法执行。
疑问2:Client.__init__(self, self)两次传self的原理?
首先,Client.__init__的第一个self是Python构造方法的常规要求——调用父类构造时必须传入当前子类的实例(也就是TestApp的实例),这是为了让父类的初始化逻辑作用在子类实例上。
而第二个self,是因为Client的构造需要一个wrapper对象(用来处理回调,比如updateMktDepth这类方法)。由于TestApp同时继承了Wrapper,它的实例本身就具备Wrapper的所有能力(包括你重写的那些回调方法),所以直接把当前实例传给Client的wrapper参数,就能让Client在触发回调时,直接调用TestApp自身实现的那些方法,不用再单独创建一个Wrapper实例,相当于把Client和Wrapper的功能合并到了同一个实例里。
内容的提问来源于stack exchange,提问作者Chris

