python - 通过 win32com 中的属性覆盖 setter

标签 python visio win32com

我使用 win32com 从 Python 控制 Visio。

获取和设置形状表值非常简单:

print(shp.CellsU('PinX').ResultStr(''))
# and
shp.CellsU('PinX').FormulaU = '1'

到目前为止一切顺利,但我想要一个更短的语法,通过覆盖 setter 和 getter 来得到类似的东西:

print(shp.PinX)
# and
shp.PinX = '1'

所以我去找了一处特性:

ShapeClass = type(shp)

def SetPinX(self,value):
    self.CellsU('PinX').FormulaU = value

def GetPinX(self):
    return self.CellsU('PinX').ResultStr('')

ShapeClass.PinX = property(GetPinX,SetPinX)

现在奇怪的结果 - getter 工作正常(print(shp.PinX) 给出预期值),但 setter 不起作用。

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~\AppData\Local\conda\conda\envs\YG_Package_1\lib\site-packages\win32com\client\__init__.py in __setattr__(self, attr, value)
    478                 try:
--> 479                         args, defArgs=self._prop_map_put_[attr]
    480                 except KeyError:

KeyError: 'PinX'

During handling of the above exception, another exception occurred:

AttributeError                            Traceback (most recent call last)
<ipython-input-28-23f68b65624d> in <module>()
----> 1 shp.PinX= '1'

~\AppData\Local\conda\conda\envs\YG_Package_1\lib\site-packages\win32com\client\__init__.py in __setattr__(self, attr, value)
    479                         args, defArgs=self._prop_map_put_[attr]
    480                 except KeyError:
--> 481                         raise AttributeError("'%s' object has no attribute '%s'" % (repr(self), attr))
    482                 self._oleobj_.Invoke(*(args + (value,) + defArgs))
    483         def _get_good_single_object_(self, obj, obUserName=None, resultCLSID=None):

AttributeError: '<win32com.gen_py.Microsoft Visio 15.0 Type Library.IVShape instance at 0x85710888>' object has no attribute 'PinX'

dir(ShapeClass) 很好地显示了 PinX 属性。

用自己的类进行测试也有效。因此,错误并不在于我实现该属性的方式。

我怀疑 win32com 存在 setter 被覆盖的问题。

有人知道如何解决这个问题吗?

最佳答案

win32com.client.DispatchBaseClass 基类使用 __setattr__ 拦截所有属性设置访问。这会影响您的属性(property)对象;属性 setter 仅由默认的 object.__setattr__ 实现调用,而不是由 win32com 使用的自定义方法调用。

所以,是的,shp.PinX = '1' 调用DispatchBaseClass.__setattr__('PinX', '1'),甚至如果类上定义了一个名为 PinX 的数据描述符,那么就会失败,因为它只支持 COM 接口(interface)定义的属性。

您必须在此处重写 __setattr__ 方法以首先检查可用属性。您可以子类 DispatchBaseClass 或特定生成的类,或者我们可以直接对 win32com 进行猴子补丁:

import inspect
from win32com.client import DispatchBaseClass

dispatch_setattr = DispatchBaseClass.__setattr__

def allow_datadescriptor_setattr(self, name, value):
    # for non-private names, check if the attribute exists on the class
    # and is a data descriptor. If so, use object.__setattr__ to permit
    # the data descriptor to intercept attribute setting
    if name[:1] != '_' and inspect.isdatadescriptor(getattr(type(self), name, None)):
        return object.__setattr__(self, name, value)
    # private name, or doesn't exist on the class, or not a data descriptor
    # invoke the original win32com dispatch __setattr__
    dispatch_setattr(self, name, value)

DispatchBaseClass.__setattr__ = allow_datadescriptor_setattr

以上允许任何 descriptor with a __set__ or __delete__ method拦截对其名称的赋值,而不仅仅是 property 对象。

关于python - 通过 win32com 中的属性覆盖 setter ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55431363/

相关文章:

sql - 什么是 Visio Enterprise Architect 的良好替代品?

visio - 如何在 Visio 中绘制来自多个路径的一组重复步骤?

python - win32com.client.Dispatch + Cherrypy = CoInitialize 尚未调用

Python 正则表达式 - re.search() 与 re.findall()

python - 自动生成 PDF

python - 如何使用 odoo 中的 ORM 方法从表中获取不同的值

python - Win32com python : impossible to access a chart on excel

python - 我无法使用 Homebrew 软件安装 python,因为没有可用的瓶子

.net - 提高 .net 中 Visio 自动化的性能 - 创建包含大量形状和形状数据的图表

python - 如何使用Python(win32com)在Word中插入书签?