I can't figure out why this program is failing.
#!/usr/bin/env python
from __future__ import division, print_function
from future_builtins import *
import types
import libui as ui
from PyQt4 import QtCore
import sip
p = ui.QPoint()
q = QtCore.QPoint()
def _q_getattr(self, attr):
print("get %s" % attr)
value = getattr(sip.wrapinstance(self.myself(), QtCore.QPoint), attr)
print("get2 %s returned %s" % (attr, value))
return value
p.__getattr__ = types.MethodType(_q_getattr, p)
print(p.__getattr__('x')()) # Works! Prints "0"
print(p.x()) # AttributeError: 'QPoint' object has no attribute 'x'
I used Boost.Python to create libui, which exposes the class QPoint. I aso included PyQt4, which has a sip-exposed QPoint. I'm trying to accomplish a mapping between the two types.
I checked that p
is a new-style class, so why isn't __getattr__
being called for p.x()
?
Method Resolution Order(MRO) it denotes the way a programming language resolves a method or attribute. Python supports classes inheriting from other classes. The class being inherited is called the Parent or Superclass, while the class that inherits is called the Child or Subclass.
When implementing multiple inheritance, Python builds a list of classes to search as it needs to resolve which method has to be called when one is invoked by an instance. As the name suggests, the method resolution order will search the depth-first, then go left to right.
To get the MRO of a class, you can use either the __mro__ attribute or the mro() method. The __mro__ attribute returns a tuple, but the mro() method returns a python list. To take a more complex example that also demonstrates depth-first search, we take 6 classes. We can represent this with the following diagram.
Python provides two ways to get the method resolution order of a class - __mro__ attribute or mro() method. With the help of these methods, we can display the order of method in which they are resolved. Let's understand the following example.
This is somewhat similar to the issue someone else has encountered just yesterday. In short, it seems like special methods (like __getattr__
, __str__
, __repr__
, __call__
and so on) aren't overridable in new-style class instance, i.e. you can only define them in its type.
And here's an adaptation of my solution for that problem which should hopefully work for yours:
def _q_getattr(self, attr):
print("get %s" % attr)
return getattr(self, 'x')
def override(p, methods):
oldType = type(p)
newType = type(oldType.__name__ + "_Override", (oldType,), methods)
p.__class__ = newType
override(p, { '__getattr__': _q_getattr})
print(p.__getattr__('x')()) # Works! Prints "0"
print(p.x()) # Should work!
I suggest that you not attempt to expose QPoint in boost python. You should be able to register converters to/from python with boost that will use the SIP api functions to convert QPoint from/to python as the sip objects.
I've done it, but not recently enough to give more details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With