2011-05-07 65 views
5

我不明白为什么这个程序失败。Python的方法分辨率神秘

#!/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()

+0

我建议首先尝试用多重继承继承。 – Keith 2011-05-07 20:21:36

+0

如果我是子类,是不是有底层C++ QPoint对象的两个副本?那么,在Python中设置成员变量对C++是不可见的,反之亦然? – 2011-05-07 20:25:24

+0

难道你不能只用一个或另一个?或者使用混合类?只是问,我不熟悉Qt和Boost。 – Keith 2011-05-07 20:31:46

回答

5

这与昨天的someone else has encountered有点类似。简而言之,似乎特殊方法(如__getattr__,__str__,__repr__,__call__等)在新式实例中不可覆盖,即您只能在其类型中定义它们。

下面是我对这个问题应该有希望为您的工作解决方案的适应性:

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! 
+0

是的,这就是为什么我建议使用系统(例如使用继承)而不是尝试“黑客”。但我不确定在这种情况下如何使用两个包装类。将不得不进行调查。 – Keith 2011-05-07 20:36:23

+0

我没有SIP的经验,所以我不知道。如果继承不起作用,那么我的解决方案将无法工作。但是,如果继承不起作用,恐怕你能做的事情很少,因为所有这些特殊的方法只能在类型级别上被覆盖。 – 2011-05-07 20:41:17

+0

@Boav:感谢Python课程('__getattr__'必须设置为类型级别。)解决了这个谜团。我会考虑你的解决方案并回复你。 – 2011-05-07 20:54:25

1

我建议你不要试图揭露QPoint升压蟒。你应该能够使用boost来注册转换器到/从python,它将使用SIP api函数将QPoint从/转换为python作为sip对象。

我已经做到了,但最近还不够详细。

+0

这听起来像我想要的。我会高兴。请让我知道你是否偶然遇到你的旧解决方案。谢谢。 – 2011-05-07 20:52:20

+0

@Neil G,我以前的解决方案是在以前的雇主svn。我可能不会绊倒它。 – 2011-05-07 21:08:02

+0

哈哈,没关系没问题。到目前为止,我发现了这个:http://gitorious.org/avogadro/avogadro/blobs/e297c37550a093deaf515229a4c4c040a882d5b0/libavogadro/src/python/sip.cpp将更多地研究它。 – 2011-05-07 21:22:58

1

这是如何整合PyQt4的和boost :: python的一个例子

首先我们必须定义包装/解包功能来处理裸指针

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) 
+0

谢谢!谢谢!这很棒! – 2012-02-06 09:58:33