@@ -92,6 +92,41 @@ PyArray_LookupSpecial(PyObject *obj, char const *name)
92
92
return maybe_get_attr ((PyObject * )tp , name );
93
93
}
94
94
95
+ /*
96
+ * Stripped down version of PyObject_GetAttrString(obj, name) that does not
97
+ * raise PyExc_AttributeError.
98
+ *
99
+ * This allows it to avoid creating then discarding exception objects when
100
+ * performing lookups on objects without any attributes.
101
+ *
102
+ * Returns attribute value on success, NULL without an exception set if
103
+ * there is no such attribute, and NULL with an exception on failure.
104
+ */
105
+ static NPY_INLINE PyObject *
106
+ _maybe_get_attr_unicode (PyObject * obj , char const * name , PyObject * name_unicode )
107
+ {
108
+ PyTypeObject * tp = Py_TYPE (obj );
109
+ PyObject * res = (PyObject * )NULL ;
110
+
111
+ /* Attribute referenced by (char *)name */
112
+ if (tp -> tp_getattr != NULL ) {
113
+ res = (* tp -> tp_getattr )(obj , (char * )name );
114
+ if (res == NULL && PyErr_ExceptionMatches (PyExc_AttributeError )) {
115
+ PyErr_Clear ();
116
+ }
117
+ }
118
+ /* Attribute referenced by (PyObject *)name */
119
+ else if (tp -> tp_getattro != NULL ) {
120
+ res = (* tp -> tp_getattro )(obj , name_unicode );
121
+ if (res == NULL && PyErr_ExceptionMatches (PyExc_AttributeError )) {
122
+ PyErr_Clear ();
123
+ }
124
+ }
125
+ printf ("_maybe_get_attr: %ld\n" , (long )res );
126
+
127
+ return res ;
128
+ }
129
+
95
130
/*
96
131
* Lookup a special method "__array_ufunc__", following the python approach of looking up
97
132
* on the type object, rather than on the instance itself.
@@ -118,24 +153,7 @@ PyArray_Lookup_Array_UFunc(PyObject *obj)
118
153
if (_is_basic_python_type (tp )) {
119
154
return NULL ;
120
155
}
121
-
122
- PyObject * res = (PyObject * )NULL ;
123
-
124
- /* Attribute referenced by (char *)name */
125
- if (tp -> tp_getattr != NULL ) {
126
- res = (* tp -> tp_getattr )(obj , (char * )name );
127
- if (res == NULL && PyErr_ExceptionMatches (PyExc_AttributeError )) {
128
- PyErr_Clear ();
129
- }
130
- }
131
- /* Attribute referenced by (PyObject *)name */
132
- else if (tp -> tp_getattro != NULL ) {
133
- res = (* tp -> tp_getattro )(obj , name_unicode );
134
- if (res == NULL && PyErr_ExceptionMatches (PyExc_AttributeError )) {
135
- PyErr_Clear ();
136
- }
137
- }
138
- return res ;
156
+ return _maybe_get_attr_unicode ((PyObject * )tp , name , name_unicode );
139
157
}
140
158
141
159
/*
0 commit comments