python 中 COM 对象的正确类型提示是什么?
What is the correct type hinting for COM Objects in python?
我在 python 中使用 COM 对象将可编程接口公开给第 3 方软件。这是通过使用 win32com.client
中的 Dispatch
实现的。我的项目也一直在使用 python.3.7 中的类型提示,但是我不确定您将如何为类型提示定义这些 COM 对象的类型。这个问题与我拥有的所有 COM 对象有关,一个真实的例子是 Microsoft Direct X Recordset: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()
并使用 returned 类型:
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
这不是 return 适合定义 COM 对象的类型。我相信我可以使用 TypeVar('T')
和 Generic[]
创建一个抽象基础 class,但是我不确定是否有更多 pythonic/better 可用的替代方法。
谢谢
恐怕您不幸 运行 进入了输入 Python 的限制之一。特别是:
- 据我所知,在 Typeshed 或第三方模块中没有 pywin32 库的类型存根。这意味着没有关于该类型应该是什么的现有规范参考。
- 动态分派到任意对象将限制仅使用类型提示可以表达的内容(假设
Dispatch
确实分派到任意对象)。
因此,我推荐以下三种方法之一:
如果您不想对 returned 类型做任何假设并将其视为不透明的 blob,则 return 类型只是 object
.这是最严格和类型安全的选项,因为符合 PEP 484 的类型检查器将允许调用者仅使用所有 Python 对象中存在的方法,例如 __str__
或 __eq__
。
如果您不想对 returned 类型做任何假设,但又不对其使用施加任何限制,请将 return 类型设置为 Any,动态类型。这是最宽松和最不安全的操作:你说输出是某种动态类型并告诉类型检查器让调用者随心所欲地使用 returned 对象。
这是“默认选项”,可以这么说:因为没有可用于 pywin32 的类型存根,类型检查器将回退到假设 Dispatch(...)
有一个 return 类型的 Any .
如果您确定 returned 类型总是有一些特定的方法或属性可用,那么您将 return 类型设为 Protocol。协议基本上可以让你进行 结构子类型化 :任何碰巧实现协议方法和属性的 class 都被认为是该协议的子类型,即使 class 不是' 以任何方式从协议继承。如果您熟悉 Go,协议基本上就像 Go 的接口。
您可能想在这里创建一个专用的 create_adodb_recordset(...)
函数,这样您就可以更全面地自定义 return 类型。
我在 python 中使用 COM 对象将可编程接口公开给第 3 方软件。这是通过使用 win32com.client
中的 Dispatch
实现的。我的项目也一直在使用 python.3.7 中的类型提示,但是我不确定您将如何为类型提示定义这些 COM 对象的类型。这个问题与我拥有的所有 COM 对象有关,一个真实的例子是 Microsoft Direct X Recordset: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()
并使用 returned 类型:
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
这不是 return 适合定义 COM 对象的类型。我相信我可以使用 TypeVar('T')
和 Generic[]
创建一个抽象基础 class,但是我不确定是否有更多 pythonic/better 可用的替代方法。
谢谢
恐怕您不幸 运行 进入了输入 Python 的限制之一。特别是:
- 据我所知,在 Typeshed 或第三方模块中没有 pywin32 库的类型存根。这意味着没有关于该类型应该是什么的现有规范参考。
- 动态分派到任意对象将限制仅使用类型提示可以表达的内容(假设
Dispatch
确实分派到任意对象)。
因此,我推荐以下三种方法之一:
如果您不想对 returned 类型做任何假设并将其视为不透明的 blob,则 return 类型只是
object
.这是最严格和类型安全的选项,因为符合 PEP 484 的类型检查器将允许调用者仅使用所有 Python 对象中存在的方法,例如__str__
或__eq__
。如果您不想对 returned 类型做任何假设,但又不对其使用施加任何限制,请将 return 类型设置为 Any,动态类型。这是最宽松和最不安全的操作:你说输出是某种动态类型并告诉类型检查器让调用者随心所欲地使用 returned 对象。
这是“默认选项”,可以这么说:因为没有可用于 pywin32 的类型存根,类型检查器将回退到假设
Dispatch(...)
有一个 return 类型的 Any .如果您确定 returned 类型总是有一些特定的方法或属性可用,那么您将 return 类型设为 Protocol。协议基本上可以让你进行 结构子类型化 :任何碰巧实现协议方法和属性的 class 都被认为是该协议的子类型,即使 class 不是' 以任何方式从协议继承。如果您熟悉 Go,协议基本上就像 Go 的接口。
您可能想在这里创建一个专用的
create_adodb_recordset(...)
函数,这样您就可以更全面地自定义 return 类型。