Тайна разрешения метода Python - PullRequest
5 голосов
/ 07 мая 2011

Я не могу понять, почему эта программа не работает.

#!/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'

Я использовал Boost.Python для создания libui, который предоставляет класс QPoint.Я также включил PyQt4, который имеет QPoint, доступный для глотка.Я пытаюсь выполнить сопоставление между двумя типами.

Я проверил, что p является классом нового стиля, так почему же __getattr__ не вызывается для p.x()?

Ответы [ 3 ]

5 голосов
/ 08 мая 2011

Это похоже на проблему , с которой кто-то еще столкнулся только вчера. Короче говоря, кажется, что специальные методы (такие как __getattr__, __str__, __repr__, __call__ и т. Д.) Не могут быть переопределены в классе нового стиля instance , т.е. вы можете только определите их в своем типе.

А вот адаптация моего решения для этой проблемы, которая, мы надеемся, сработает для вашей:

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!
1 голос
/ 06 февраля 2012

Это пример того, как интегрировать PyQt4 и boost :: python

Прежде всего мы должны определить функцию wrap / unwrap, чтобы иметь дело с голыми указателями

long int unwrap(QObject* ptr) {
    return reinterpret_cast<long int>(ptr);
}

template <typename T>
T* wrap(long int ptr) {
    return reinterpret_cast<T*>(ptr);
}

после этого мы должны зарегистрировать все классы, которые мы хотим интегрировать в

class_<QObject, QObject*, boost::noncopyable>("QObject", no_init)
    .def("unwrap", unwrap)
    .def("wrap", make_function( wrap<QObject>, return_value_policy<return_by_value>() ))
    .staticmethod("wrap");

class_<QWidget, bases<QObject>, QWidget*, boost::noncopyable>("QWidget")
    .def("wrap", make_function( wrap<QWidget>, return_value_policy<return_by_value>() ))
    .staticmethod("wrap");

class_<QFrame, bases<QWidget>, QFrame*, boost::noncopyable>("QFrame")
    .def("wrap", make_function( wrap<QFrame>, return_value_policy<return_by_value>() ))
    .staticmethod("wrap");

class_<QLabel, bases<QFrame>, QLabel*, boost::noncopyable>("QLabel")
    .def("wrap", make_function( wrap<QLabel>, return_value_policy<return_by_value>() ))
    .staticmethod("wrap");

и, например, у нас есть класс, который работает с .. QLabel:

class worker: public QObject {
...
void add_label(QLabel*);
};

мы также должны выставить этот класс на python:

class_<worker, bases<QObject>, worker*, boost::noncopyable>("worker")
        .def("add_label", &worker::add_label);

теперь мы готовы к взаимодействию, на C ++ - размер сделать что-то вроде этого

worker* w = new worker;
main_namespace["worker"] = boost::ref(w);

питон:

from PyQt4.Qt import *
import sip
import mylib as MyLib

#...

#If you are using QApplication on C++-size you don't need to create another one

lb = QLabel("label from PyQt4!")

lb_ptr = sip.unwrapinstance(f)

my_lb = MyLib.QLabel.wrap(lb_ptr)

worker.add_label(my_lb)

В другом случае, если вы не хотите отправлять свой собственный Q-объект в PyQt4:

QLabel* lb = new QLabel("C++ label");
main_namespace["lb"] = boost::ref(lb);

питон:

from PyQt4.Qt import *
import sip
import mylib as MyLib

#...

my_lb_ptr = lb.unwrap()

qt_lb = sip.wrapinstance(my_lb_ptr, QLabel)

А это мой настоящий маленький помощник:

from PyQt4.Qt import *
import sip

def toQt(object, type):
    ptr = object.unwrap()
    return sip.wrapinstance(ptr, type)

def fromQt(object, type):
    ptr = sip.unwrapinstance(object)
    return type.wrap(ptr)
1 голос
/ 08 мая 2011

Я предлагаю вам не пытаться выставить QPoint в boost Python.Вы должны иметь возможность регистрировать конвертеры в / из Python с надстройкой, которые будут использовать функции API SIP для преобразования QPoint из / в Python в качестве объектов sip.

Я сделал это, но не достаточно недавно, чтобы дать более подробную информацию.

...