Python属性& Swig [英] Python Properties & Swig

查看:139
本文介绍了Python属性& Swig的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用swig为某些C ++代码创建python绑定。我似乎遇到了一个问题尝试创建python属性从一些访问器函数我有类似如下的方法:

 类播放器{
public:
void entity(Entity * entity);
Entity * entity()const;
};

我试图使用python属性函数创建一个属性,但似乎包装类swig生成不是

解决方案



如何使用swig创建属性? / div>

哦,这是棘手的(和乐趣)。 SWIG 不认为这是一个产生@属性的机会:我认为如果没有真正仔细地做,就会太容易滑落并识别大量的误报。然而,由于SWIG不会生成C ++,所以在Python中使用小的元类仍然完全可以做到这一点。



下面,让我们说一个Math类,让我们设置和获取一个名为pi的整数变量。然后我们可以使用这个代码:



example.h



  ifndef EXAMPLE_H 
#define EXAMPLE_H

class Math {
public:
int pi()const {
return this-> _pi;
}

void pi(int pi){
this-> _pi = pi;
}

private:
int _pi;
};

#endif



example.i



 %模块示例

%{
#define SWIG_FILE_WITH_INIT
#includeexample.h
%}

[基本上example.h重复]



cpp



  #includeexample.h

util.py



  class PropertyVoodoo(type):
一个元类,当* class *初始化时初始化,而不是
对象。因此,我们可以自由地绕过类
方法,特别是描述符。

def __init __(cls,* a):
#OK,所以使用OP中描述的样式的C ++属性列表存储在__properties__魔术变量
#班上。
for prop in cls .__ properties__:

#获取访问器。
def fget(self):
#使用super获取SWIG类。我们必须使用super
#,因为我们唯一的信息是
#类对象本身(cls)。这不是最多的
#强大的做事方式,但工作时SWIG
#类是唯一的超类。
s = super(cls,self)

#现在获取C ++方法并调用其operator()。
return getattr(s,prop)()

#设置访问器。
def fset(self,value):
#同上。
s = super(cls,self)

#调用它的重载运算符(int value)来设置它。
return getattr(s,prop)(value)

#Python中的属性是描述符,它是类中的
#静态变量。所以,这里我们创建
#静态变量并将其设置为属性。
setattr(cls,prop,property(fget = fget,fset = fset))

#type()需要额外的参数,我们没有使用
#继承。 (父类作为参数传递为
#元类协议的一部分。)通常a = [< some swig
#class>]现在。
super(PropertyVoodoo,cls).__ init __(* a)

#另一个工作:SWIG自动覆盖
#__setattr__。正常的Python类使用对象.__ setattr__,
#这就是我们在这里使用。它不是真的重要的
#__setattr__我们使用,只要我们跳过SWIG类在
#继承链,因为SWIG的__setattr__将跳过我们刚刚创建的
#属性。
def __setattr __(self,name,value):
#只对列出的属性执行此操作。
如果在cls .__中的名称属性:
对象.__ setattr __(self,name,value)
else:
#同上。
s = super(cls,self)

s .__ setattr __(name,value)

#注意__setattr__应该是一个实例方法,
#因此自我。简单地将它分配给类属性
#将确保它是一个实例方法;也就是说,它将*不*
#魔法地变成静态/类方法。
cls .__ setattr__ = __setattr__



somefile.py



  import example 
从util import PropertyVoodoo

类Math(example.Math):
__properties__ = ['pi ']
__metaclass__ = PropertyVoodoo

m = Math()
print m.pi
m.pi = 1024
print m.pi
m.pi = 10000
print m.pi

所以最终结果就是必须为每个SWIG Python类创建一个包装类,然后键入两行:一个标记应该转换属性的方法,一个用于引入元类。


I am attempting to create python bindings for some C++ code using swig. I seem have run into a problem trying to create python properties from some accessor functions I have for methods like the following:

class Player {
public:
  void entity(Entity* entity);
  Entity* entity() const;
};

I tried creating a property using the python property function but it seems that the wrapper classes swig generates are not compatible with it at least for setters.

How do you create properties using swig?

解决方案

Ooh, this is tricky (and fun). SWIG doesn't recognize this as an opportunity to generate @property: I imagine it'd be all too easy to slip up and recognize lots of false positives if it weren't done really carefully. However, since SWIG won't do it in generating C++, it's still entirely possible to do this in Python using a small metaclass.

So, below, let's say we have a Math class that lets us set and get an integer variable named "pi". Then we can use this code:

example.h

#ifndef EXAMPLE_H
#define EXAMPLE_H

class Math {
 public:
    int pi() const {
        return this->_pi;
    }

    void pi(int pi) {
        this->_pi = pi;
    }

 private:
    int _pi;
};

#endif

example.i

%module example

%{
    #define SWIG_FILE_WITH_INIT
    #include "example.h"
%}

[essentially example.h repeated again]

example.cpp

#include "example.h"

util.py

class PropertyVoodoo(type):
    """A metaclass. Initializes when the *class* is initialized, not
    the object. Therefore, we are free to muck around the class
    methods and, specifically, descriptors."""

    def __init__(cls, *a):
        # OK, so the list of C++ properties using the style described
        # in the OP is stored in a __properties__ magic variable on
        # the class.
        for prop in cls.__properties__:

            # Get accessor.
            def fget(self):
                # Get the SWIG class using super. We have to use super
                # because the only information we're working off of is
                # the class object itself (cls). This is not the most
                # robust way of doing things but works when the SWIG
                # class is the only superclass.
                s = super(cls, self)

                # Now get the C++ method and call its operator().
                return getattr(s, prop)()

            # Set accessor.
            def fset(self, value):
                # Same as above.
                s = super(cls, self)

                # Call its overloaded operator(int value) to set it.
                return getattr(s, prop)(value)

            # Properties in Python are descriptors, which are in turn
            # static variables on the class. So, here we create the
            # static variable and set it to the property.
            setattr(cls, prop, property(fget=fget, fset=fset))

        # type() needs the additional arguments we didn't use to do
        # inheritance. (Parent classes are passed in as arguments as
        # part of the metaclass protocol.) Usually a = [<some swig
        # class>] right now.
        super(PropertyVoodoo, cls).__init__(*a)

        # One more piece of work: SWIG selfishly overrides
        # __setattr__. Normal Python classes use object.__setattr__,
        # so that's what we use here. It's not really important whose
        # __setattr__ we use as long as we skip the SWIG class in the
        # inheritance chain because SWIG's __setattr__ will skip the
        # property we just created.
        def __setattr__(self, name, value):
            # Only do this for the properties listed.
            if name in cls.__properties__:
                object.__setattr__(self, name, value)
            else:
                # Same as above.
                s = super(cls, self)

                s.__setattr__(name, value)

        # Note that __setattr__ is supposed to be an instance method,
        # hence the self. Simply assigning it to the class attribute
        # will ensure it's an instance method; that is, it will *not*
        # turn into a static/classmethod magically.
        cls.__setattr__ = __setattr__

somefile.py

import example
from util import PropertyVoodoo

class Math(example.Math):
    __properties__ = ['pi']
    __metaclass__  = PropertyVoodoo

m = Math()
print m.pi
m.pi = 1024
print m.pi
m.pi = 10000
print m.pi

So the end result is just that you have to create a wrapper class for every SWIG Python class and then type two lines: one to mark which methods should be converted in properties and one to bring in the metaclass.

这篇关于Python属性&amp; Swig的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆