[python-win32] extending com objects

Ross McKerchar it at crummock.com
Fri May 25 11:38:41 CEST 2007


Tim Golden wrote:
> This -- just in case you haven't come across the expression --
> is called monkey-patching. It's a slightly general-purpose
> example of it, but it's something which is usefully easy
> to do in Python. (Consequently, it's easy to abuse but...)

Ah right - nice to know my dodgy hack is a member of a well known family :)

> Frankly, I never even thought of doing it. You may already
> have covered this, but it does have one or corner-cases
> you might want to consider. If one of your methods needs
> to completely cover one of the original ones *and* to call
> the original one as well (say to get the data you're going
> to wrap) then you have to do something a bit smarter than
> the straight __dict__.update you're doing there. Not very
> much harder, but you'd have to do it.

Yep - currently I'm just using it to add some basic convenience 
functions (particularly __iter__, __getitem__, and the likes) so it's 
not an issue. I suppose a slightly less naive technique would rename 
conflicts first.

>  > The beauty of this is that I
>> dont have to worry about wrapping the results of any functions as I'm 
>> always dealing with the real com class, just with some extra methods 
>> added. 
> 
> Presumably, then, if the original COM class exposed,
> say, a .GetGroups method which returned a list of
> groups, each of which you wanted to wrap, in this
> implementation, you'd add a .MyGetGroups method which
> called the original and wrapped the result?

It's simpler than that: as long as you've monkey-patched the original 
COM groups class, the groups returned by the GetGroups method will 
already have your methods: no need to wrap.

Of course this presumes it's easy to find the Group class: my current 
implementation assumes everything is in the same module, hence the

#find parent class of same name
parentclass = getattr(com_genpy_module,klass.__name__)
parentclass.__dict__.update(klass.__dict__)

If your com library returned com classes from another library (is that 
even possible?) and hence used another genpy module then I suppose you'd 
have more problems...

 > Others may point out hidden flaws which I've missed,
 > and I'll be glad to hear them, but if it works for
 > you... :)

I've already come across some minor problems (not currently affecting me 
too much but could become major headaches), mainly to do with existing 
magic used by pythoncom:

1) Using your own attributes gets tricky as they pythoncom tries to 
automatically assign them to the underlying com object. I've been 
bypassing the __setattr__ override by doing "self.__dict__['spam'] = 
'ham'" which would could get tedious rather quickly...

2) Defining your own __init__ causes all sorts of problems :)

3) You "take over" the com classes: that is, comclass.__class__ is your 
class, not the original com_class: any kind on explicit introspection 
(isinstance, etc.), within pythoncom or existing client code could now 
fail. Again a less naive patching process that didn't overwrite 
everything blindly should be easy.

-ross


More information about the Python-win32 mailing list