Python方法解析之谜

发布于 2024-11-05 20:19:01 字数 809 浏览 0 评论 0原文

我不明白为什么这个程序失败了。

#!/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,它有一个 sip 暴露的 QPoint。我正在尝试完成两种类型之间的映射。

我检查了 p 是一个新式类,那么为什么 __getattr__ 没有被 px() 调用呢?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冷情妓 2024-11-12 20:19:01

这与其他人遇到的问题有些相似 就在昨天。简而言之,似乎特殊方法(如 __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!

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!
泡沫很甜 2024-11-12 20:19:01

我建议你不要尝试在 boost python 中公开 QPoint。您应该能够使用 boost 注册与 python 之间的转换器,该转换器将使用 SIP api 函数将 QPoint 与 python 之间转换为 sip 对象。

我已经做到了,但最近还不够提供更多细节。

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.

帝王念 2024-11-12 20:19:01

这是一个如何集成 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);

python:

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);

python:

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)

This is an example how to integrate PyQt4 and boost::python

first of all we must define wrap/unwrap function to deal with bare pointers

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

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

after that we must register all classes we want integrate to

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");

and for example we have class that works with.. QLabel:

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

we must expose this class to python too:

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

now we a ready to interaction,
on C++-size do something like this

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

python:

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)

In other case if you wan't send you own Q-object to PyQt4 :

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

python:

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

#...

my_lb_ptr = lb.unwrap()

qt_lb = sip.wrapinstance(my_lb_ptr, QLabel)

And this is my real little helper:

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文