Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python method resolution mystery

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()?

like image 966
Neil G Avatar asked May 07 '11 19:05

Neil G


People also ask

What is __ MRO __ in Python?

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.

What is method resolution in Python?

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.

How MRO is calculated in Python?

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.

How do I find the order of resolution in Python?

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.


2 Answers

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!
like image 172
Boaz Yaniv Avatar answered Sep 28 '22 10:09

Boaz Yaniv


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.

like image 29
Winston Ewert Avatar answered Sep 28 '22 10:09

Winston Ewert