[PYTHON MATRIX-SIG] changes to fix __array__()
Chris Chase SRM
chris.chase@jhuapl.edu
Fri, 29 Nov 1996 15:38:39 -0500
I am using NumPy-1.0a5.tar and Python 1.4.
I was trying to use the __array__(self, typecode=None) interface for
getting an object as an array and found that it did not work. I
traced the problem to array_fromobject() in arrayobject.c.
I have made the necessary changes to array_fromobject() in
arrayobject.c. I also made corrections to refecrence handling of
Python objects in the same function (according to Lutz's PP book both
PyEval_CallObject() and PyObject_GetAttrString() pass pass owenership
of result, i.e. it is already INCREF'd and must be DECREF'd when
finished).
As a result of all this I found that asarray() did not use
PyArray_FromObject() but instead copies via PyArray_CopyFromObject
when using the __array__() interface. To make it use
PyArray_FromObject(), I moved asarray() in multiarray.c instead of in
Numeric.py.
An example of the fixed behavior of the __array__ interface and
asarray():
class a:
def __init__(self):
self.a = arange(8)
def __array__(self,t=None):
if t: return asarray(self.a,t)
return asarray(self.a)
b = a()
c = array(b)
c[2] = -9
>>> c
0 1 -9 3 4 5 6 7
>>> b.a
0 1 2 3 4 5 6 7
d = asarray(b)
d[2] = -9
>>> b.a
0 1 -9 3 4 5 6 7
According to the documentation for array the interface is given as
"array(sequence, typecode=None)" which seems to indicate that None is
valid value for typecode. However, None is not a valid value and
typecode is not a keyword argument. The documentation should be
changed. Although, I think that it would be better to let typecode be
a possible keyword argument and let None be a valid value that gets
mapped to PyArray_NOTYPE (in arrayobject.h).
Anyway, for the __array__ and asarray changes I modified
arrayobject.c, multiarray.c and Numeric.py. The context diffs created
in the NumPy directory are below, which I believe are suitable for the
patch program, are below.
Chris Chase
===================================================================
RCS file: arrayobject.c,v
retrieving revision 1.1
diff -c5 -r1.1 arrayobject.c
*** arrayobject.c 1996/11/28 07:10:25 1.1
--- arrayobject.c 1996/11/29 19:13:11
***************
*** 1612,1641 ****
}
#define ByCopy 1
#define Contiguous 2
! PyObject *array_fromobject(PyObject *op, int type, int min_depth, int max_depth, int flags) {
! PyObject *r;
!
r = NULL;
! if (!PyArray_Check(op) && PyObject_HasAttrString(op, "__array__")) {
PyObject *ap, *arglist;
if (type == PyArray_NOTYPE) {
arglist = Py_BuildValue("()");
} else {
arglist = Py_BuildValue("(c)", type);
}
! ap = PyObject_GetAttrString(op, "__array__");
! r = PyEval_CallObject(ap, arglist);
Py_DECREF(arglist);
!
! Py_XINCREF(r);
! }
!
if (type == PyArray_NOTYPE) {
type = PyArray_ObjectType(op, 0);
}
if (PyArray_Check(op) && (((PyArrayObject *)op)->descr->type_num != PyArray_OBJECT ||
--- 1612,1646 ----
}
#define ByCopy 1
#define Contiguous 2
! PyObject *array_fromobject(PyObject *op_in, int type, int min_depth, int max_depth, int flags) {
! PyObject *r, *op;
!
r = NULL;
! if (!PyArray_Check(op_in) && PyObject_HasAttrString(op_in, "__array__")) {
! /* __array__(self, type=None) method interface
! for getting an object as an array. */
PyObject *ap, *arglist;
if (type == PyArray_NOTYPE) {
arglist = Py_BuildValue("()");
} else {
arglist = Py_BuildValue("(c)", type);
}
! ap = PyObject_GetAttrString(op_in, "__array__");
! op = PyEval_CallObject(ap, arglist);
! Py_DECREF(ap);
Py_DECREF(arglist);
! if (op == NULL) return NULL;
! } else {
! op = op_in;
! Py_INCREF(op);
! }
!
if (type == PyArray_NOTYPE) {
type = PyArray_ObjectType(op, 0);
}
if (PyArray_Check(op) && (((PyArrayObject *)op)->descr->type_num != PyArray_OBJECT ||
***************
*** 1648,1673 ****
Py_INCREF(op);
r = op;
}
} else {
if (type > PyArray_NTYPES) type = PyArray_DescrFromType(type)->type_num;
! if ((r = PyArray_Cast((PyArrayObject *)op, type)) == NULL) return NULL;
}
} else {
r = Array_FromSequence(op, type, min_depth,max_depth);
! if (r == NULL) {
! if (min_depth <= 0) {
! PyErr_Clear();
! r = PyArray_FromScalar(op, type);
! } else {
! return NULL;
! }
}
}
if (r == NULL) return NULL;
! if(!PyArray_Check(r)) {
PyErr_SetString(PyExc_ValueError, "Internal error array_fromobject not producing an array");
return NULL;
}
if (min_depth != 0 && ((PyArrayObject *)r)->nd < min_depth) {
Py_DECREF(r);
--- 1653,1677 ----
Py_INCREF(op);
r = op;
}
} else {
if (type > PyArray_NTYPES) type = PyArray_DescrFromType(type)->type_num;
! r = PyArray_Cast((PyArrayObject *)op, type);
}
} else {
r = Array_FromSequence(op, type, min_depth,max_depth);
! if (r == NULL && min_depth <= 0) {
! PyErr_Clear();
! r = PyArray_FromScalar(op, type);
}
}
+ /* finished with op */
+ Py_DECREF(op);
+
if (r == NULL) return NULL;
! if (!PyArray_Check(r)) {
PyErr_SetString(PyExc_ValueError, "Internal error array_fromobject not producing an array");
return NULL;
}
if (min_depth != 0 && ((PyArrayObject *)r)->nd < min_depth) {
Py_DECREF(r);
rcsdiff: RCS/multiarray.c,v: No such file or directory
rcsdiff: Numeric/RCS/Numeric.py,v: No such file or directory
custer [121]> ../misc/makepatch
../misc/makepatch
===================================================================
RCS file: arrayobject.c,v
retrieving revision 1.1
diff -c5 -r1.1 arrayobject.c
*** arrayobject.c 1996/11/28 07:10:25 1.1
--- arrayobject.c 1996/11/29 19:13:11
***************
*** 1612,1641 ****
}
#define ByCopy 1
#define Contiguous 2
! PyObject *array_fromobject(PyObject *op, int type, int min_depth, int max_depth, int flags) {
! PyObject *r;
!
r = NULL;
! if (!PyArray_Check(op) && PyObject_HasAttrString(op, "__array__")) {
PyObject *ap, *arglist;
if (type == PyArray_NOTYPE) {
arglist = Py_BuildValue("()");
} else {
arglist = Py_BuildValue("(c)", type);
}
! ap = PyObject_GetAttrString(op, "__array__");
! r = PyEval_CallObject(ap, arglist);
Py_DECREF(arglist);
!
! Py_XINCREF(r);
! }
!
if (type == PyArray_NOTYPE) {
type = PyArray_ObjectType(op, 0);
}
if (PyArray_Check(op) && (((PyArrayObject *)op)->descr->type_num != PyArray_OBJECT ||
--- 1612,1646 ----
}
#define ByCopy 1
#define Contiguous 2
! PyObject *array_fromobject(PyObject *op_in, int type, int min_depth, int max_depth, int flags) {
! PyObject *r, *op;
!
r = NULL;
! if (!PyArray_Check(op_in) && PyObject_HasAttrString(op_in, "__array__")) {
! /* __array__(self, type=None) method interface
! for getting an object as an array. */
PyObject *ap, *arglist;
if (type == PyArray_NOTYPE) {
arglist = Py_BuildValue("()");
} else {
arglist = Py_BuildValue("(c)", type);
}
! ap = PyObject_GetAttrString(op_in, "__array__");
! op = PyEval_CallObject(ap, arglist);
! Py_DECREF(ap);
Py_DECREF(arglist);
! if (op == NULL) return NULL;
! } else {
! op = op_in;
! Py_INCREF(op);
! }
!
if (type == PyArray_NOTYPE) {
type = PyArray_ObjectType(op, 0);
}
if (PyArray_Check(op) && (((PyArrayObject *)op)->descr->type_num != PyArray_OBJECT ||
***************
*** 1648,1673 ****
Py_INCREF(op);
r = op;
}
} else {
if (type > PyArray_NTYPES) type = PyArray_DescrFromType(type)->type_num;
! if ((r = PyArray_Cast((PyArrayObject *)op, type)) == NULL) return NULL;
}
} else {
r = Array_FromSequence(op, type, min_depth,max_depth);
! if (r == NULL) {
! if (min_depth <= 0) {
! PyErr_Clear();
! r = PyArray_FromScalar(op, type);
! } else {
! return NULL;
! }
}
}
if (r == NULL) return NULL;
! if(!PyArray_Check(r)) {
PyErr_SetString(PyExc_ValueError, "Internal error array_fromobject not producing an array");
return NULL;
}
if (min_depth != 0 && ((PyArrayObject *)r)->nd < min_depth) {
Py_DECREF(r);
--- 1653,1677 ----
Py_INCREF(op);
r = op;
}
} else {
if (type > PyArray_NTYPES) type = PyArray_DescrFromType(type)->type_num;
! r = PyArray_Cast((PyArrayObject *)op, type);
}
} else {
r = Array_FromSequence(op, type, min_depth,max_depth);
! if (r == NULL && min_depth <= 0) {
! PyErr_Clear();
! r = PyArray_FromScalar(op, type);
}
}
+ /* finished with op */
+ Py_DECREF(op);
+
if (r == NULL) return NULL;
! if (!PyArray_Check(r)) {
PyErr_SetString(PyExc_ValueError, "Internal error array_fromobject not producing an array");
return NULL;
}
if (min_depth != 0 && ((PyArrayObject *)r)->nd < min_depth) {
Py_DECREF(r);
rcsdiff: RCS/multiarray.c,v: No such file or directory
===================================================================
RCS file: Numeric/Numeric.py,v
retrieving revision 1.1
diff -c5 -r1.1 Numeric/Numeric.py
*** Numeric/Numeric.py 1996/11/29 20:24:40 1.1
--- Numeric/Numeric.py 1996/11/29 20:25:12
***************
*** 31,40 ****
--- 31,41 ----
return m.astype(typecode)
else:
return m
#Include some functions straight from multiarray
+ asarray = multiarray.asarray
array = multiarray.array
zeros = multiarray.zeros
fromstring = multiarray.fromstring
take = multiarray.take
reshape = multiarray.reshape
***************
*** 235,251 ****
def nonzero(a):
"""Return the indices of the elements of a which are not zero, a must be 1d
"""
return repeat(arange(len(a)), not_equal(a, 0))
! def asarray(a, typecode=None):
! if type(a) == arraytype and (typecode == None or typecode == a.typecode()):
! return a
! elif typecode == None:
! return array(a)
! else:
! return array(a, typecode)
#Move this into C to do it right!
def shape(a):
return asarray(a).shape
--- 236,252 ----
def nonzero(a):
"""Return the indices of the elements of a which are not zero, a must be 1d
"""
return repeat(arange(len(a)), not_equal(a, 0))
! ## def asarray(a, typecode=None):
! ## if type(a) == arraytype and (typecode == None or typecode == a.typecode()):
! ## return a
! ## elif typecode == None:
! ## return array(a)
! ## else:
! ## return array(a, typecode)
#Move this into C to do it right!
def shape(a):
return asarray(a).shape
=================
MATRIX-SIG - SIG on Matrix Math for Python
send messages to: matrix-sig@python.org
administrivia to: matrix-sig-request@python.org
=================