2010-06-22 6 views
7

J'ai du code pour interfacer Python avec C++ qui fonctionne bien mais chaque fois que je le regarde, je pense qu'il doit y avoir une meilleure façon de le faire. Du côté C++ il y a un type 'variant' qui peut gérer une gamme fixe de types basiques - int, real, string, vector de variants, etc. J'ai du code utilisant l'API Python pour convertir des types Python équivalents. Il ressemble à quelque chose comme ceci:Python C API: Activer le type PyObject

variant makeVariant(PyObject* value) 
{ 
    if (PyString_Check(value)) { 
    return PyString_AsString(value); 
    } 
    else if (value == Py_None) { 
    return variant(); 
    } 
    else if (PyBool_Check(value)) { 
    return value == Py_True; 
    } 
    else if (PyInt_Check(value)) { 
    return PyInt_AsLong(value); 
    } 
    else if (PyFloat_Check(value)) { 
    return PyFloat_AsDouble(value); 
    } 
    // ... etc 

Le problème est le if-else enchaîné. Il semble appeler une instruction switch, ou une table ou une carte de fonctions de création qui est codée par un identifiant de type. Autrement dit, je veux être capable d'écrire quelque chose comme:

return createFunMap[typeID(value)](value); 

Basé sur une skim de l'API docs il n'a pas été évident que la meilleure façon est d'obtenir le « typeID » ici directement. Je vois que je peux faire quelque chose comme ceci:

PyTypeObject* type = value->ob_type; 

Cela semble me fait rapidement aux informations de type, mais quelle est la façon la plus propre à utiliser pour se rapporter à l'ensemble limité de types que je suis intéressé?

Répondre

3

D'une certaine manière, je pense que vous avez répondu à votre propre question.

Quelque part, vous allez devoir sélectionner une fonctionnalité basée sur des données. La façon de faire cela en C est d'utiliser des pointeurs de fonction.

Créer une carte de type_objet-> mappeurs de fonction ... où chaque fonction a une interface clairement définie.

variant PyBoolToVariant(PyObject *value) { 
    return value == Py_True; 
} 

Map<PyTypeObject*,variant* (PyObject*)> function_map; 

function_map.add(PyBool, PyBoolToVariant); 

Maintenant votre makeVariant peut ressembler à ceci.

variant makeVariant(PyObject *value) { 
    return (*function_map.get(value->ob_type))(value); 
} 

La partie difficile va obtenir la bonne syntaxe pour l'objet Map. En outre, je suppose qu'il existe un objet Map que vous pouvez utiliser qui prend les paramètres de type (<PyTypeObject*, variant*(PyObject*)).

Je n'ai probablement pas tout à fait obtenu la syntaxe correcte pour le deuxième type de la carte. Ce devrait être un pointeur vers une fonction qui prend un pointeur et retourne un pointeur vers une variante.

J'espère que c'est utile.

+0

Merci. La partie function_map.add (PyBool, ...) de votre réponse était suffisante pour que je puisse regarder au bon endroit dans le document de l'API, je pense que cela doit être PyBool_Type plutôt que PyBool. Quelles sont les * valeurs * de PyTypeObject que je devais utiliser comme clé de ma carte et cela répond. – Bob