简短回答:如果您更改此行:
outlook = client.Dispatch('Outlook.Application')
至:
outlook = client.dynamic.Dispatch('Outlook.Application')
您的原始代码适用于GetNameSpace("MAPI")
(使用大写“S”)
或者,将您的代码更改为GetNamespace()
.
长答案:问题的出现是因为win32com
创建 Outlook 应用程序对象的方式,或者实际上是一般的 COM 对象。这种解释不仅限于 Python,在 VBA 和其他语言(例如 C++、C#)中也可以看到。
您可以通过两种方式连接或绑定到 COM 对象及其方法和属性:早期绑定或后期绑定。
早期绑定:在这里,所有关于对象支持的方法和属性的信息都提前被调用代码知道。此信息位于与提供对象的应用程序一起提供的类型库中。有时它位于单独的.tlb
文件中,也可能位于应用程序的可执行文件中(Excel 就是这种情况)。类型库包含关于类、它们的方法以及可能定义的任何常量的所有信息。这有时被称为“自定义”界面。调用的函数必须与类型库方法完全匹配,并且函数名区分大小写。
后期绑定:在这里,调用应用程序对对象的前期知之甚少。该对象公开了一个通用函数调用接口,即Dispatch接口。应用程序可以尝试调用此接口上的任何函数,这些函数可能有效也可能无效。在运行时,Dispatch 接口按名称查找请求的函数,并尝试将其与数字标识符或 ID 匹配。如果返回一个有效的 Id,则使用参数列表调用该函数。这里的一个关键点是函数名查找不区分大小写。
一个松散的类比可能是去餐馆吃点东西。
你可以去餐厅门口看看外面的菜单。您已经根据其供应的美食选择了这家餐馆。这将告诉您有哪些食物可供选择,并可能分为开胃菜、主菜和甜点。作为用餐者,您可以放心,在开门之前,您将能够坐下并订购您选择的物品。这是早期绑定:您有很多前期信息。
或者,您可以打开大街上的任何一扇门,走进去,坐下来要食物,也许可以指定“牛排”和“薯条”。您可能事先不知道这是餐厅还是牙医。如果您选择了正确的门,并且菜单上有牛排和薯条,那就太好了。如果没有,您将遇到问题或“错误”。这是后期绑定,你必须为事情不会像你希望的那样发展做好准备。
一般来说,早期绑定完成了一次匹配函数和参数的所有艰苦工作,然后每次调用都很快。它还允许调用应用程序创建包装类,以反映正在创建的对象的类模型。但并非每个对象都提供类型库,并且一些调用应用程序不具备生成包装器的能力。后期绑定更通用,需要很少的对象的前期知识,但执行起来自然更慢。在许多应用程序中,用户不会注意到速度差异。
最后,回到win32com
。这是 COM 对象的 Python 包装器,可以在早期或后期绑定模式下运行。大多数提供 COM 对象的应用程序(例如 Outlook、Excel 等)都支持这两种模式:所谓的双界面。win32com
有两种绑定路径:win32com.client.gencache
早期绑定和win32com.dynamic
后期绑定。
win32com
早期绑定涉及读取对象类型库的包并gencache
用于makepy
生成 python 代码来包装自定义接口。此代码存储在 python 包文件系统中以供以后使用(具体位置取决于您的配置)。另dynamic
一种方法只是尝试后期绑定。
在更高级别,该win32com.client.Dispatch()
函数将为您选择一种绑定方法。如果自定义接口的包装文件存在,那么它将用于早期绑定。如果他们不这样做,则使用后期绑定。
这里的关键点是,如果您从未(在您的应用程序或其他 python 应用程序中)调用outlook=win32com.client.gencache.EnsureDispatch('Outlook.Application')
过,您将不会生成用于提前绑定到 Outlook 应用程序对象的包装代码缓存。因此,调用win32com.client.Dispatch()
将退回到使用后期绑定。
在这种情况下,使用后期绑定,无论您调用outlook.GetNameSpace()
、outlook.GetNamespace()
还是确实,Python 代码都可以工作outlook.GeTnAmEsPaCe()
,因为后期绑定 Dispatch 接口上的函数查找不区分大小写。
但是,如果在某个时间点(今天、昨天、一年前)gencache.EnsureDispatch('Outlook.Application')
调用了该函数(并且在 OP 链接到的示例代码中调用了该函数),则将生成包装函数,win32com.client.Dispatch('Outlook.Application')
并将执行最佳操作并使用早期绑定。这里的问题是函数名称现在区分大小写,并且现在只有 outlook.GetNamespace()
小写的 's' 才能工作。这是显示拼写的MS 文档。GetNamespace()
这不是特定于 Python / win32com。您可以在 VBA 中观察到相同的效果。
如果你这样写:
Dim ol As Object
Set ol = CreateObject("Outlook.Application")
Dim ns As Object
Set ns = ol.GeTnaMeSpAcE("MAPI")
它会正常工作。这是因为除非您包含“Microsoft Outlook 16.0 对象库”(使用工具 | 参考),否则 VBA 使用不区分大小写的后期绑定。
但是,如果您确实包含了类型库引用并使用了类类型,那么您现在正在使用早期绑定:
Dim ol As Outlook.Application
Set ol = CreateObject("Outlook.Application")
Dim ns As Outlook.Namespace
Set ns = ol.GetNamespace("MAPI")
VBA 编辑器可能会强制执行正确的区分大小写的拼写。
虽然 VBA 也很困惑(至少在我的设置中):当您键入时, Dim ns as Outlook. ...
VBA 会提示NameSpace
完成(大写“S”),但一旦选择,IntelliSense 将Dim ns as Outlook.Namespace
使用小写“s”更正它!