2011-05-07 63 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