python中COM对象的正确类型提示是什么?

时间:2020-02-19 11:48:48

标签: python com type-hinting

我正在python中使用COM对象将可编程接口公开给第三方软件。这可以通过使用Dispatch中的win32com.client来实现。我的项目也一直在使用python.3.7中的类型提示,但是我不确定如何为类型提示而定义这些COM对象的类型。这个问题与我拥有的所有COM对象有关,一个真实的示例是Microsoft Direct X记录集:Dispatch("ADODB.Recordset")

from win32com.client import Dispatch
def create_my_com_object_instance(input_arg: Dict[str, Union[str, float, int]]) -> <type_of_com_object_here>:
    my_instance = Dispatch("ADODB.Recordset")
    # Set attributes/call methods of this instance here ... 
    return my_instance

在上面的代码片段中,我将'type_of_com_object_here'替换为COM对象类型。

我的第一个想法只是在实例上调用type()并使用返回的类型:

x = Dispatch("ADODB.Recordset")
x
Out[1]: <win32com.gen_py.Microsoft ActiveX Data Objects 6.1 Library._Recordset instance at 0x83848456>
type(x)
Out[2]: win32com.gen_py.B691E011-1797-432E-907A-4D8C69339129x0x6x1._Recordset._Recordset
x.__class__
Out[3]: win32com.gen_py.B691E011-1797-432E-907A-4D8C69339129x0x6x1._Recordset._Recordset

这不会返回用于定义COM对象的合适类型。我相信我可以使用TypeVar('T')Generic[]创建一个抽象基类,但是我不确定是否有更多的pythonic /更好的替代方法。

谢谢

1 个答案:

答案 0 :(得分:2)

很遗憾,您不幸遇到了使用Python进行输入的限制之一。特别是:

  1. 据我所知,在Typeshed或第3方模块中都没有pywin32库的类型存根。这意味着该类型应该是什么,尚无规范的参考。
  2. 动态分配给任意对象将限制仅使用类型提示就可以表达的内容的限制(假设Dispatch确实确实分配给了任意对象)。

因此,我推荐以下三种方法之一:

  1. 如果您不希望对返回的类型做任何假设,并将其视为不透明的Blob,请将返回类型设为object。这是最严格和类型安全的选项,因为符合PEP 484的类型检查器将使调用者仅使用所有Python对象(例如__str____eq__)中存在的方法。

  2. 如果您不希望对返回的类型做任何假设,但也没有对其使用施加任何限制,请将返回类型设为动态类型Any。这是最宽松,最不安全的操作:您说输出是某种动态类型,并告诉类型检查器让调用者随意使用返回的对象。

    可以这么说,这是“默认选项”:由于pywin32没有可用的类型存根,因此类型检查器将退回到假设Dispatch(...)的返回类型为Any的地方。

    < / li>
  3. 如果您确定返回的类型将始终具有某些可用的特定方法或属性,则您将返回类型设为Protocol。协议基本上可以让您进行结构子类型化:碰巧实现协议方法和属性的任何类都被视为该协议的子类型,即使该类不是以任何方式继承自协议。如果您熟悉Go,则协议基本上类似于Go的接口。

    您可能要在此处创建专用的create_adodb_recordset(...)函数,以便可以更全面地自定义返回类型。