C++ Klasse in Python importieren

Objektorientierte Skriptsprache: (python.org)
Antworten
Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

C++ Klasse in Python importieren

Beitrag von Glocke » Mi Nov 07, 2012 6:33 pm

Ich habe eine (aus meiner Sicht) "schöne" Möglichkeit gefunden, in C++ implementierte Klassen in Python zu importieren: SWIG.

example.hpp

Code: Alles auswählen

#ifndef EXAMPLE_H
#define EXAMPLE_H

class Foo {

	protected:
		int value;

	public:
		double bar;
		Foo(int value);
		void set_value(int value);
		int get_value();

};

#endif
example.cpp

Code: Alles auswählen

#include "example.hpp"

Foo::Foo(int value) {
	this->value = value;
	this->bar = 1.0;
}

void Foo::set_value(int value) {
	this->value = value;
}

int Foo::get_value() {
	return this->value;
}
example.i

Code: Alles auswählen

%module example
%{ 
    #define SWIG_FILE_WITH_INIT
    #include "example.hpp"
%}
%include "example.hpp"
Und gebaut habe ich das so:
swig -c++ -python example.i
g++ -fPIC -c example.cpp example_wrap.cxx -I/usr/include/python2.7/
g++ -shared example_wrap.o example.o -o _example.so
Dabei entstehen example.py und _example.so. Offensichtlich sind beide notwendig um das Modul example in Python zu importieren.

Code: Alles auswählen

Python 2.7.3 (default, Aug  1 2012, 05:16:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from example import Foo
>>> f = Foo(15)
>>> f.bar
1.0
>>> f.value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "example.py", line 74, in <lambda>
    __getattr__ = lambda self, name: _swig_getattr(self, Foo, name)
  File "example.py", line 55, in _swig_getattr
    raise AttributeError(name)
AttributeError: value
>>> f.get_value()
15
>>> f.set_value(12)
>>> f.get_value()
12
>>> f.set_value(12.4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "example.py", line 83, in set_value
    def set_value(self, *args): return _example.Foo_set_value(self, *args)
TypeError: in method 'Foo_set_value', argument 2 of type 'int'
Dabei werden offenbar auch Typsicherheit und Sichtbarkeit beibehalten.

Was sagt ihr dazu, ist das so sinnvoll?

LG Glocke

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: C++ Klasse in Python importieren

Beitrag von Glocke » Di Jan 08, 2013 9:48 am

Hey, ich muss das ganze mal erweitern. Anbei etwas sinnloser Beispielcode (C++): http://pastebin.com/J0SpBnC7 und http://pastebin.com/FTC4Vv17.

Dazu die "Engine.i" für SWIG:

Code: Alles auswählen

%module Engine
%include "std_string.i"
%include "std_map.i"
%{ 
    #define SWIG_FILE_WITH_INIT
    #include "Engine.hpp"
%}
%include "Engine.hpp"
Gebaut habe ich mit:

Code: Alles auswählen

#!/bin/bash

clear
echo "Fetch from C++"
swig -c++ -python $1.i
echo "Compile Source"
g++ -fPIC -c $1.cpp $1_wrap.cxx -I/usr/include/python2.7/
echo "Link as Library"
g++ -shared $1_wrap.o $1.o -o _$1.so
echo "Done"
und dann "./build Engine"

Und ausgeführt (in der Python Konsole) folgendes: http://pastebin.com/03x7Xh7r
Ich schaffe es nicht, der map etwas zuzuweisen ... Was mache ich falsch?

LG Glocke

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8516
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: C++ Klasse in Python importieren

Beitrag von Xin » Di Jan 08, 2013 10:42 am

Bitte kein Pastebin. Kopiert den Kram bitte in das Posting und im Idealfall liefert ein ZIP-Archiv mit, damit man den Kram nicht einzeln sich irgendwo zusammenklauben muss, wenn man es zum Testen selbst bauen will!

Example.hpp

Code: Alles auswählen

#include <iostream>
#include "Engine.hpp"

Engine::Engine(const std::string name, int limit) {
        this->user = new User(name);
        this->limit = limit;
}

Engine::~Engine() {
        delete this->user;
}

void Engine::run() {
        while (!(this->user->finished(this->limit))) {
                this->user->inc();
        }
}

User::User(const std::string name) {
        this->name = name;
        this->counter = 0;
}

void User::inc() {
        this->counter += 1;
        std::cout << "New value is of '" << this->name << "' is " << this->counter << std::endl;
}

bool User::finished(int limit) {
        return (this->counter >= limit);
}
Example.cpp

Code: Alles auswählen

#include <iostream>
#include "Engine.hpp"

Engine::Engine(const std::string name, int limit) {
        this->user = new User(name);
        this->limit = limit;
}

Engine::~Engine() {
        delete this->user;
}

void Engine::run() {
        while (!(this->user->finished(this->limit))) {
                this->user->inc();
        }
}

User::User(const std::string name) {
        this->name = name;
        this->counter = 0;
}

void User::inc() {
        this->counter += 1;
        std::cout << "New value is of '" << this->name << "' is " << this->counter << std::endl;
}

bool User::finished(int limit) {
        return (this->counter >= limit);
}
Konsoleneingaben:

Code: Alles auswählen

[Python 2.7.3 (default, Aug  1 2012, 05:16:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from Engine import Engine, User
>>> e = Engine("glocke", 12)
>>> e.run()
New value is of 'glocke' is 1
New value is of 'glocke' is 2
New value is of 'glocke' is 3
New value is of 'glocke' is 4
New value is of 'glocke' is 5
New value is of 'glocke' is 6
New value is of 'glocke' is 7
New value is of 'glocke' is 8
New value is of 'glocke' is 9
New value is of 'glocke' is 10
New value is of 'glocke' is 11
New value is of 'glocke' is 12
>>> u = User("foobar")
>>> print u.foo
<Swig Object of type 'std::map< int,std::string,std::less< int >,std::allocator< std::pair< int const,std::string > > > *' at 0xb7209908>
>>> u.foo[2] = "Zwei"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'SwigPyObject' object does not support item assignment
>>> u.foo.append(2, "Zwei")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: append() takes exactly one argument (2 given)
>>> u.foo.append((2, "Zwei"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SystemError: error return without exception set
Laut CPlusPlus.com unterstützt std::map gar kein append. Wie sieht's mit insert aus?
Ansonsten arbeitet die STL gerne mit Iteratoren. Du müsstest also nicht einen Index übergeben, sondern den passenden Iterator, z.B. u.foo.end().
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: C++ Klasse in Python importieren

Beitrag von Glocke » Di Jan 08, 2013 3:02 pm

Xin hat geschrieben:Bitte kein Pastebin. Kopiert den Kram bitte in das Posting
Okay Chef :)
Xin hat geschrieben:Laut CPlusPlus.com unterstützt std::map gar kein append. Wie sieht's mit insert aus?
Ansonsten arbeitet die STL gerne mit Iteratoren. Du müsstest also nicht einen Index übergeben, sondern den passenden Iterator, z.B. u.foo.end().
Ich war auch verwundert. Aber laut Python-Funktion "dir()" hat u.foo kein begin, end, insert oder so, aber ein append, next und owns ... :?

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8516
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: C++ Klasse in Python importieren

Beitrag von Xin » Di Jan 08, 2013 3:15 pm

Glocke hat geschrieben:Ich war auch verwundert. Aber laut Python-Funktion "dir()" hat u.foo kein begin, end, insert oder so, aber ein append, next und owns ... :?
Kurz gegooglet und bei swig.org gelandet.

std::map wird wohl deutlich bearbeitet, bevor es an Python rausgeht.

Es gibt wohl ein da einige Includes (http://www.swig.org/Doc1.3/Library.html ... pp_library), die man sich mal ansehen müsste.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3092
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: C++ Klasse in Python importieren

Beitrag von cloidnerux » Di Jan 08, 2013 3:36 pm

Code: Alles auswählen

>>> u.foo.append(2, "Zwei")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: append() takes exactly one argument (2 given)
append kann doch nur 1 Element anfügen, also müsste der Aufruf doch so aussehen:

Code: Alles auswählen

>>> u.foo.append(2);
>>> u.foo.append("Zwei");
Redundanz macht wiederholen unnötig.
quod erat expectandum

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: C++ Klasse in Python importieren

Beitrag von Glocke » Mi Jan 09, 2013 8:33 am

Xin hat geschrieben:std::map wird wohl deutlich bearbeitet, bevor es an Python rausgeht.
Wahrscheinlich fahre ich eh besser, wenn ich zum modifizieren der std::map ne Methode verwende und die map als protected deklariere, oder?

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8516
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: C++ Klasse in Python importieren

Beitrag von Xin » Mi Jan 09, 2013 10:55 am

Glocke hat geschrieben:
Xin hat geschrieben:std::map wird wohl deutlich bearbeitet, bevor es an Python rausgeht.
Wahrscheinlich fahre ich eh besser, wenn ich zum modifizieren der std::map ne Methode verwende und die map als protected deklariere, oder?
Ich vermute es, aber vom Prinzip solltest Du Dir erst anschauen, was Dir swig so anbietet.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Antworten