klasse in extension

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

Hallo allerseits,
ist es möglich eine Klasse in eine Extension einzufügen?
Über "PyMethodDef" definiere ich ja die Methoden des Extension-Moduls A.
Kann ich da jetzt irgendwie ein anderes Extension-Modul B als "nested class" hinzufügen?

Daniel
BlackJack

@hypnoticum: Was hast Du denn genau vor? Methoden eines Moduls sind ja eigentlich Funktionen. Und willst Du die Funktionen von Modul B auch als Funktionen in Modul A binden? Warum? Und muss das in C passieren? In Python ist das Zusammenführen von Namen aus verschiedenen Modulen um so vieles einfacher. Eine ``import``-Zeile pro Modul genügt.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

Ich sitze noch immer an der Strukturierung meines Projekts.
vgl. meinen Thread: "logische Struktur anlegen".

Ich will halt innerhalb meines Python-Scripts eine Instanz der Klasse "Gerät" erzeugen.
Die Klasse Gerät hat Methoden die als C-Extensions geschrieben werden.

Weiterhin soll die Klasse "Gerät" "nested Classes" "Block_n" (n = 0, 1, 2, ..., i) enthalten.
Die Klassen "Block_n" haben ebenfalls Methoden die als C-Extensions geschrieben werden.
Diese Methoden sind in j Gruppen zu je einer Quelldatei "FunctionGroup_nm" (m = 0, 1, 2, ..., j) organisiert.

Am Ende will ich

Code: Alles auswählen

Data = Gerät.Block_n.FunktionGroup_nm_Funktion_k()
schreiben und im Projekt entsprechende Namensräume haben.
BlackJack

@hypnoticum: Ich bin immer noch von den Begrifflichkeiten verwirrt, was da jetzt was ist. Wenn `Gerät` und `Block_n` Klassen sind, dann passt Deine Schreibweise irgendwo nicht, da fehlen dann nämlich Klammern um auch tatsächlich Exemplare zu erstellen. Verschachtelte Klassen wären in Python auch eher ungewöhnlich. Klassen werden in aller Regel auf Modulebene definiert. Der Name `PyMethodDef()` ist in Bezug auf Module ein wenig verwirrend, weil es da eigentlich Funktionen sind.

Und ich hoffe mal, dass die Namen nicht tatsächlich die Nummern enthalten. Das wäre IMHO eine sehr unschöne API.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@BlackJack:
>> da fehlen dann nämlich Klammern um auch tatsächlich Exemplare zu erstellen.
wo fehlen Klammern? Wenn ich eine Instanz von "Gerät.Block_n" erzeugt habe, kann ich doch dann so auf die Methode zugreifen?

>> Klassen werden in aller Regel auf Modulebene definiert.
Hilft mir jetzt nicht weiter (Wo denn sonst, wenn nicht in einem Modul?). Mach doch mal einen Lösungsvorschlag anstatt zu sagen was man wie nicht macht.

>> Wenn `Gerät` und `Block_n` Klassen sind
eigentlich sind es Module bzw. Extensions. Die C-Funktionen werden bei der Verwendung in Python dann zu Methoden des jeweiligen Moduls,
wobei eine Verschachtelung erfolgen soll in der meine Verzeichnis und Dateistruktur mit dem Punkt-Operator wiedergegeben wird:

Code: Alles auswählen

Data = Gerät.Block_n.FunktionGroup_nm_Funktion_k(Parameterliste)
BlackJack

@hypnoticum: Wenn Du eine Instanz von `Gerät.Block_n` erzeugt hast, wobei ich jetzt mal davon ausgehe, dass `Block_n` eine Klasse ist, weil Du ja sagst Du willst davon eine Instanz erzeugen und darauf Methoden aufrufen -- dann greifst Du auf die Methoden *nicht* über `Gerät.Block_n.irgendwas` zu, denn das ist ja gar nicht die Instanz sondern der Typ/die Klasse.

Du nanntest `Gerät` und `Block_n` Klassen, aber es sind anscheinend Module. Darum war/bin ich verwirrt. Wenn beides Module sind und `Block_n` eine *Funktion* `FunktionGroup_nm_Funktion_k` enthält, dann war Deine Aufrufzeile richtig. Funktionen in Erweiterungsmodulen werden trotz dem dass sie Funktionen sind, mit `PyDefMethod`-Strukturen beschrieben. Ist wie gesagt etwas ungünstig benannt in dem Fall. Auf der Python-Seite hat es dann aber den richtigen Namen, da steht dann laut und deutlich "function":

Code: Alles auswählen

>>> import _test
>>> _test
<module '_test' from '_test.so'>
>>> _test.foobar
<built-in function foobar>
Ich kann keinen Lösungsvorschlag machen wenn ich nicht verstehe was Du machen willst. Und anscheinend willst Du auch gar keine Klassen verschachteln, denn es sind ja Module und keine Klassen. In dem Fall musst Du einfach nur die `Block_n`-Module importieren (z.B. mit `PyImport_ImportModule()`) und zu Deinem Modul mit `PyModule_AddObject()` hinzufügen.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@BlackJack:
Vielen Dank für den Tip, aber ich weiss noch nicht wie ich das damit umsetzen soll.
Der Inhalt der Datei cBlock.c (das mit dem einrücken klappt hier irgendwie nicht so gut):

Code: Alles auswählen

#include <Python.h>
#include "cBlockFunctions.h"

static PyMethodDef pyBlockI_methods[] = {{"pyBlockI_a", cBlockI_a, METH_VARARGS, "Performs some a-function"}, \
							   {"pyBlockI_b", cBlockI_b, METH_VARARGS, "Performs some b-function"}, \
							   {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC initpyBlockI(void){
      Py_InitModule("pyBlockI", pyBlockI_methods);
};
/*
PyObject *PyFunGpIModule = NULL;
PyFunGpIModule = PyImport_ImportModule("pyBlockFunctionGroupI");

PyModule_AddObject(pyBlockI, \
			     "PyFunGpIModule", \
			     (PyObject *)&PyFunGpIModule);
*/
Ein Problem was ich nicht lösen kann ist, dass ich ja hier anscheinend zwei Module referenzieren muss die noch nicht erzeugt sind.
Dann brauche ich wohl zwei Durchgänge?
Mit diesem Python-Script habe ich bisher die Extensions erzeugt:

Code: Alles auswählen

import sys
import os
from distutils.core import setup, Extension

# clean up / python setup.py clean --all
if os.path.exists("build"):
    try:
        os.remove("build")
    except:
        pass
    
sys.argv.append('install') 

BlockI_modul = Extension("pyBlockI", 
                          sources = ['C/cBlockI.c',
                                     'C/cBlockFunctions.c'],
                          depends = ['C/cBlockFunctions.h'],
                          include_dirs = ['H:/Python/Projects/Py_Workspace/Minimal/src/Device/BlockI/C']) 

BlockFunctionGroupI_modul = Extension("pyBlockFunctionGroupI", 
                                      sources = ['C/cBlockFunctionGroupI.c',],
                                      depends = [],
                                      include_dirs = ['H:/Python/Projects/Py_Workspace/Minimal/src/Device/BlockI/C'])

setup( 
     name = "BlockI", 
     version = "1.0", 
     description = "Test C-Extension", 
     ext_package='Minimal/BlockI',
     ext_modules = [BlockI_modul, BlockFunctionGroupI_modul] 
     )
btw: ich weiss auch nicht wie ich die option "python setup.py clean --all" im Script einfügen soll.
Zuletzt geändert von hypnoticum am Freitag 1. April 2011, 14:02, insgesamt 1-mal geändert.
BlackJack

@hypnoticum: Zwei Durchgänge!? Pack das Auskommentierte mal in die Funktion `initpyBlockI()` und speichere den Rückgabewert von `Py_InitModule` in einer Variable mit dem Namen `pyBlock1`. Das ist ja das Modulobjekt wo Du die anderen Module als Attribute hinzufügen möchtest.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@Blackjack:
Danke, habe ich gemacht. Kompilieren lief auch ohne Fehler durch, aber wie komme ich jetzt an die Funktionen des Moduls "BlockFunctionGroupI"?

Code: Alles auswählen

PyMODINIT_FUNC initpyBlockI(void){
	PyObject *PyFunGpIModule, *PyBlkModule;

	PyBlkModule = Py_InitModule("pyBlockI", pyBlockI_methods);
	PyFunGpIModule = PyImport_ImportModule("BlockFunctionGroupI");

	PyModule_AddObject(PyBlkModule, \
						"PyFunGpIModule", \
					   (PyObject *)&PyFunGpIModule);
};
C:/Python26/Lib/site-packages/Minimal/BlockI\BlockI.pyd
----------------------------------------------------------------------
Help on module BlockI:
NAME
BlockI
FILE
c:\python26\lib\site-packages\minimal\blocki\blocki.pyd
FUNCTIONS
pyBlockI_a(...)
Performs some a-function
pyBlockI_b(...)
Performs some b-function
['__doc__', '__file__', '__name__', '__package__', 'pyBlockI_a', 'pyBlockI_b']
Zuletzt geändert von hypnoticum am Freitag 1. April 2011, 14:33, insgesamt 1-mal geändert.
BlackJack

@hypnoticum: Dein `BlockI`-Modul sollte eigentlich ein `PyFunGpIModule`-Attribut haben. Da vermute ich mal das Du Dich im Namen vertan hast und das eigentlich unter dem Namen `BlockFunctionGroupI` dem Modul hinzufügen wolltest.

Wenn das Attribut nicht vorhanden ist, dann ist mindestens einer der drei Funktionsaufrufe nicht erfolgreich gewesen. Da müsstest Du mal die Rückgabewerte überprüfen.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

Code: Alles auswählen

sys.path.append("C:/Python26/Lib/site-packages/Minimal/BlockI")
import BlockI
print BlockI.PyFunGpIModule.cFun_I_a(1)
liefert:
AttributeError: 'module' object has no attribute 'PyFunGpIModule'
und beim Kompilieren der Module lief mit dem oben gezeigten Script mingw ohne meckern durch.

Wie überprüfe ich die Rückgabewerte?
BlackJack

@hypnoticum: Das ist ja auch ein Laufzeitfehler dass Du zur Laufzeit mögliche Probleme einfach ignorierst.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@BlackJack:
mag sein - nur wie finde ich den Fehler?
kann ich mir ausgeben lassen welche / bzw ob module jetzt in dem "BlockI"-Modul integriert sind?
Antworten