Extension problem: Is my type object duplicated?

Jonas Bjering jonas at kryfos.com
Wed Jun 11 05:39:25 EDT 2003


Hello,
I am writing a Python Extension in C and have encountered a problem,
explicitly created (Explicit as in v = Vector(1, 2, 3)) instances of
my object has a ob_type pointer that refers to a different address
than the address of my static type object. How can this be?

It create trouble for me when objects I create as a result of
operations have ob_type set to the address of my static type object
(as I expected all objects of my type would have) and when I compare
ob_type to check they are of the same type it fails.

Specifically in my case the symptom is I get v + v working while v + v
+ v fails as the result of the first addition has a different ob_type
ptr from v.

I include my type definition and the relevant functions below. If
someone can tell me what I do wrong I would be very appreciated.

Thank you
Jonas Bjering


header..

#ifndef _PYVECTOR_H_
#define _PYVECTOR_H_

#include "Python.h"
#include "vector.h"

typedef struct 
{
    PyObject_HEAD
	CVector3<float> _vector;
} CVectorObject;

int InitVector( CVectorObject* self, PyObject* args, PyObject* kwds );

PyObject* AddVector( CVectorObject* self,  PyObject* args );
int CoerceVector( PyObject ** o1, PyObject ** o2 );
PyObject* VectorRichCompare(PyObject* o1, PyObject* o2, int cmpOp);
PyObject* VectorRepr( CVectorObject* self );


static PyMethodDef vectorMethods[] = 
{
	{NULL, NULL, NULL, NULL}
};

static PyNumberMethods vectorAsNumeric = {
	(binaryfunc) AddVector,	// binaryfunc nb_add;
	0,	// binaryfunc nb_subtract;
	0,	// binaryfunc nb_multiply;
	0,	// binaryfunc nb_divide;
	0,	// binaryfunc nb_remainder;
	0,	// binaryfunc nb_divmod;
	0,	// ternaryfunc nb_power;
	0,	// unaryfunc nb_negative;
	0,	// unaryfunc nb_positive;
	0,	// unaryfunc nb_absolute;
	0,	// inquiry nb_nonzero;
	0,	// unaryfunc nb_invert;
	0,	// binaryfunc nb_lshift;
	0,	// binaryfunc nb_rshift;
	0,	// binaryfunc nb_and;
	0,	// binaryfunc nb_xor;
	0,	// binaryfunc nb_or;
	(coercion) CoerceVector,	// coercion nb_coerce;
	0,	// unaryfunc nb_int;
	0,	// unaryfunc nb_long;
	0,	// unaryfunc nb_float;
	0,	// unaryfunc nb_oct;
	0,	// unaryfunc nb_hex;
	0,	// binaryfunc nb_inplace_add;
	0,	// binaryfunc nb_inplace_subtract;
	0,	// binaryfunc nb_inplace_multiply;
	0,	// binaryfunc nb_inplace_divide;
	0,	// binaryfunc nb_inplace_remainder;
	0,	// ternaryfunc nb_inplace_power;
	0,	// binaryfunc nb_inplace_lshift;
	0,	// binaryfunc nb_inplace_rshift;
	0,	// binaryfunc nb_inplace_and;
	0,	// binaryfunc nb_inplace_xor;
	0,	// binaryfunc nb_inplace_or;
	0,	// binaryfunc nb_floor_divide;
	0,	// binaryfunc nb_true_divide;
	0,	// binaryfunc nb_inplace_floor_divide;
	0	// binaryfunc nb_inplace_true_divide;
};
//	{"__add__", (PyCFunction) AddVector, METH_VARARGS, "Adds a vector
to another and returns the result."},



static PyTypeObject vectorType = {
    PyObject_HEAD_INIT(NULL)
    0,
    "pyclausewitz.Vector",
    sizeof(CVectorObject),
	0,
	(destructor) PyObject_Del,	/* tp_dealloc */
	0,							/* tp_print */
	0,					/* tp_getattr */
	0,					/* tp_setattr */
	0,					/* tp_compare */
	(reprfunc) VectorRepr,	/* tp_repr */
	&vectorAsNumeric,	/* tp_as_number */
	0,					/* tp_as_sequence */
	0,					/* tp_as_mapping */
	0,					/* tp_hash */
	0,					/* tp_call */
	0,					/* tp_str */
	0,					/* tp_getattro */
	0,					/* tp_setattro */
	0,					/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT, /* tp_flags */
	0,					/* tp_doc */
	0,					/* tp_traverse */
	0,					/* tp_clear */
	VectorRichCompare,	/* tp_richcompare */
	0,					/* tp_weaklistoffset */
	0,					/* tp_iter */
	0,									/* tp_iternext */
	vectorMethods,						/* tp_methods */
	0,									/* tp_members */
	0,									/* tp_getset */
	0,									/* tp_base */
	0,									/* tp_dict */
	0,									/* tp_descr_get */
	0,									/* tp_descr_set */
	0,									/* tp_dictoffset */
	(initproc) InitVector,				/* tp_init */
	0,									/* tp_alloc */
	PyType_GenericNew,					/* tp_new */  	
	0,									//freefunc tp_free; /* Low-level free-memory routine */
	0,									//inquiry tp_is_gc; /* For PyObject_IS_GC */
	0,									//PyObject *tp_bases;
	0,									//PyObject *tp_mro; /* method resolution order */
	0,									//PyObject *tp_cache;
	0,									//PyObject *tp_subclasses;
	0,									//PyObject *tp_weaklist;
	0,									//destructor tp_del;
#ifdef COUNT_ALLOCS
	  									///* these must be last and never explicitly initialized
*/
	0,									//int tp_allocs;
	0,									//int tp_frees;
	0,									//int tp_maxalloc;
	0,									//struct _typeobject *tp_next;
#endif
};

#endif

and the implementation...

#include "pyvector.h"
#include "text.h"

int InitVector( CVectorObject* self, PyObject* args, PyObject*
keywordvalues )
{
	float x;
	float y;
	float z;

    static char *keywords[] = {"x", "y", "z", NULL};

    if( !PyArg_ParseTupleAndKeywords(args, keywordvalues, "fff",
keywords,
                                     &x, &y, &z) )
        return -1; 
 
	self->_vector = CVector3<float>( x, y, z );

	return 0;
}

PyObject* VectorRichCompare(PyObject* o1, PyObject* o2, int cmpOp)
{
	if( !( o1->ob_type == &vectorType &&  o1->ob_type == &vectorType) )
	{
		CString errorMsg("Cannot compare " + CString( o1->ob_type->tp_name )
+ " to " + CString( o2->ob_type->tp_name ));
		PyErr_SetString( PyExc_NotImplementedError, errorMsg.GetCharPtr() );
		return NULL;
	}
	CVectorObject* v1 = reinterpret_cast<CVectorObject*>( o1 );
	CVectorObject* v2 = reinterpret_cast<CVectorObject*>( o2 );
	if( cmpOp == Py_EQ )
	{
		if( v1->_vector == v2->_vector )
		{
			Py_INCREF( Py_True );
			return Py_True;
		}
		else
		{
			Py_INCREF( Py_False );
			return Py_False;
		}

	}
	else if( cmpOp == Py_NE )
	{
		if( v1->_vector != v2->_vector )
		{
			Py_INCREF( Py_True );
			return Py_True;
		}
		else
		{
			Py_INCREF( Py_False );
			return Py_False;
		}
	}
	else
	{
		CString errorMsg("Operation not supported");
		PyErr_SetString( PyExc_NotImplementedError, errorMsg.GetCharPtr() );
		return NULL;
	}
}

int CoerceVector( PyObject ** o1, PyObject ** o2 )
{
	if( (*o1)->ob_type == &vectorType && (*o1)->ob_type == &vectorType )
	{
		Py_INCREF( *o1 );
		Py_INCREF( *o2 );
		return 0;
	}
	else
		return 1;
}

PyObject* AddVector( CVectorObject* self,  PyObject* other )
{
	if( other->ob_type != self->ob_type )
	{
		CString errorMsg("Cannot convert " + CString(
other->ob_type->tp_name ) + " to " + CString( self->ob_type->tp_name
));
		PyErr_SetString( PyExc_TypeError, errorMsg.GetCharPtr() );
		return NULL;
	}
	CVectorObject* otherAsVector = reinterpret_cast<CVectorObject*>(
other );
	CVectorObject* result = PyObject_New( CVectorObject, &vectorType );
	
	result->_vector = self->_vector + otherAsVector->_vector;
	
	return reinterpret_cast<PyObject*>( result );
}

PyObject* VectorRepr( CVectorObject* self )
{
	CString result( "Vector(" );
	result = result + CString(self->_vector.x) + ", " +
CString(self->_vector.y) + ", " + CString(self->_vector.z) + ")";
	return Py_BuildValue( "s", result.GetCharPtr() );
}




More information about the Python-list mailing list