在 win32com 中用 属性 覆盖 setter
Override setter by property in 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 工作正常(打印(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 就好了。
使用自己的 class 进行测试也有效。这样错误就不会出现在我执行 属性.
的方式中
我怀疑 win32com 有问题 setters 被覆盖。
有人知道如何解决这个问题吗?
您正在混合使用 .Formula 和 .ResultStr 方法。一个单元格可以有:
.公式
.FormulaU
。结果
.ResultU
.ResultStr
.ResultStrU
.FormulaForce
.FormulaForceU
在您的代码中,您使用 .ResultStr 获取单元格内容并使用 .FormulaU 设置单元格。我建议您查看 Visio API 以查看所有这些之间的区别。如果单元格具有受保护的 formula/value 那么您需要使用 .FormulaForce 方法。
win32com.client.DispatchBaseClass
基础class使用__setattr__
拦截所有属性设置访问。这会影响您的 属性 对象; 属性 setter 仅由默认 object.__setattr__
实现调用,而不是由 win32com
.
使用的自定义方法调用
所以是的,shp.PinX = '1'
将调用DispatchBaseClass.__setattr__('PinX', '1')
,即使在[=39上定义了一个名为PinX
的数据描述符=],这将失败,因为它只支持 COM 接口定义的属性。
您必须在此处重写 __setattr__
方法以首先检查可用属性。您可以使用 subclass DispatchBaseClass
或特定生成的 classes, 或 我们可以直接对 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
对象。
我正在使用 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 工作正常(打印(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 就好了。
使用自己的 class 进行测试也有效。这样错误就不会出现在我执行 属性.
的方式中我怀疑 win32com 有问题 setters 被覆盖。
有人知道如何解决这个问题吗?
您正在混合使用 .Formula 和 .ResultStr 方法。一个单元格可以有:
.公式
.FormulaU
。结果
.ResultU
.ResultStr
.ResultStrU
.FormulaForce
.FormulaForceU
在您的代码中,您使用 .ResultStr 获取单元格内容并使用 .FormulaU 设置单元格。我建议您查看 Visio API 以查看所有这些之间的区别。如果单元格具有受保护的 formula/value 那么您需要使用 .FormulaForce 方法。
win32com.client.DispatchBaseClass
基础class使用__setattr__
拦截所有属性设置访问。这会影响您的 属性 对象; 属性 setter 仅由默认 object.__setattr__
实现调用,而不是由 win32com
.
所以是的,shp.PinX = '1'
将调用DispatchBaseClass.__setattr__('PinX', '1')
,即使在[=39上定义了一个名为PinX
的数据描述符=],这将失败,因为它只支持 COM 接口定义的属性。
您必须在此处重写 __setattr__
方法以首先检查可用属性。您可以使用 subclass DispatchBaseClass
或特定生成的 classes, 或 我们可以直接对 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
对象。