微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否可以继承 wx.grid.Grid 并使用我自己的元类?

如何解决是否可以继承 wx.grid.Grid 并使用我自己的元类?

我有一个显示各种网格的应用程序。网格具有不同种类的功能,所以我的设计是一个处理通用网格事物的基本网格类,以及各种混合到具有基本网格的类中的功能混合:

class BaseGrid(wx.grid.Grid):

    def foo():
        return 0

class Grid_Mixin1():

    def feature():
        self.foo()

class Grid_Mixin2():
    def feature():
        self.foo()

class SpecificGrid(Mixin1,BaseGrid):
    ...

问题是我正在尝试使用类型提示,而在 mixin 中,类型检查器不知道 self.foo() 会存在,从而引发未知成员错误

我决定使用协议让静态类型检查器知道mixin符合什么:

from typing import Protocol

class MyProtocol(Protocol):

    def foo(self):
        ...

class Grid_Mixin1(MyProtocol):

    def feature():
        self.foo()

class Grid_Mixin2(MyProtocol):
    def feature():
        self.foo()

现在当我尝试使用 SpecificGrid 时,我得到了臭名昭著的

类型错误元类冲突:派生类的元类必须 是其所有基类元类的(非严格)子类

我只能假设 wx.grid.Grid 是从它自己的元类派生的?从文档中对我来说并不明显,但这是我唯一的解释。我的评估是否正确?我该怎么做才能解决这个问题?

解决方法

是的 - 它们具有不同的元类,因此您必须创建一个组合元类才能组合两个类。

这比听起来容易 - 因为 wx 和 typing 都是维护良好的代码,并且在类布局中没有内在的冲突,所以创建一个不冲突的元类只是将两个元类结合起来的问题。

然而,问题在于typing.Protocol 子类:这个层次结构不是为了指定真正的具体类——它是为了指定一个接口,描述可能代表也可能不代表它的其他类。 (这与 collections.abc 中的类不同 - 它描述了一个“协议”并且有一个 mixin 方法的实现)

这意味着当一个确实组合了 Protocol 和 wx.grid.Grid 的元类时,得到的只是另一个错误:


In [2]: import wx.grid                                                                                                                    

In [3]: wx.grid.Grid.__class__                                                                                                            
Out[3]: sip.wrappertype

In [4]: m1 = wx.grid.Grid.__class__                                                                                                       

In [5]: from typing import Protocol                                                                                                       

In [6]: m2 = Protocol.__class__                                                                                                           

In [7]: class m3(m1,m2): pass                                                                                                            

In [8]: class test(wx.grid.Grid,Protocol): pass                                                                                          
[...]
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

In [9]: class test(wx.grid.Grid,Protocol,metaclass=m3): pass                                                                            
[...]
TypeError: Protocols can only inherit from other protocols,got <class 'wx._grid.Grid'>

因此,正确的做法是根本不要从 Protocol 继承 - 实现具有协议具体实现的类,就像 mixin 一样,并正常使用它来组成您的 Grid 类 - 并拥有您的 协议层次结构就像一组虚拟类,仅包含方法、属性及其注释 - 这将从 typing.Protocol

继承

如果不想把方法和注解的声明写两次,这是可以理解的,可以声明实现协议的具体类,并使用一些代码在body

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。