在Win32com中按属性覆盖设置程序

时间:2019-03-30 12:20:04

标签: 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的设置程序有问题,而被覆盖。

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

2 个答案:

答案 0 :(得分:2)

win32com.client.DispatchBaseClass基类使用__setattr__来拦截所有属性设置访问。这会影响您的财产对象;属性设置器只能由默认的object.__setattr__实现调用,而不能由win32com使用的自定义方法调用。

是的,shp.PinX = '1' 调用DispatchBaseClass.__setattr__('PinX', '1'),即使在类上定义了名为PinX的数据描述符,也会失败仅支持COM接口定义的属性。

您必须在此处覆盖__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对象。

答案 1 :(得分:0)

您正在混合.Formula和.ResultStr方法。一个单元格可以具有:

。公式 .FormulaU 。结果 。结果U .ResultStr .ResultStrU
.FormulaForce .FormulaForceU

在代码中,您使用.ResultStr获取单元格内容,并使用.FormulaU设置单元格。我建议您查看Visio API,以了解所有这些之间的差异。如果单元格具有受保护的公式/值,则需要使用.FormulaForce方法。