Skip to content

Commit 8fe4fd9

Browse files
committed
* Objects/classobject.c, Include/classobject.h: added __getattr__
and __setattr__ support to override getattr(x, name) and setattr(x, name, value) for class instances. This uses a special hack whereby the class is supposed to be static: the __getattr__ and __setattr__ methods are looked up only once and saved in the instance structure for speed
1 parent 7a9912d commit 8fe4fd9

2 files changed

Lines changed: 111 additions & 17 deletions

File tree

Include/classobject.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3030

3131
/* Class object interface */
3232

33+
#ifdef WITH_THREAD
34+
#include "thread.h"
35+
#else
36+
#define get_thread_ident() 1L
37+
#endif
38+
3339
/* Revealing some structures (not for general use) */
3440

3541
typedef struct {
@@ -43,6 +49,12 @@ typedef struct {
4349
OB_HEAD
4450
classobject *in_class; /* The class object */
4551
object *in_dict; /* A dictionary */
52+
object *in_getattr; /* A method or NULL */
53+
object *in_setattr; /* A method or NULL */
54+
long in_ident; /* A thread ident or 0 */
55+
#ifdef WITH_THREAD
56+
type_lock *in_lock; /* A lock or NULL */
57+
#endif
4658
} instanceobject;
4759

4860
extern typeobject Classtype, Instancetype, Instancemethodtype;

Objects/classobject.c

Lines changed: 99 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -104,21 +104,23 @@ class_getattr(op, name)
104104
{
105105
register object *v;
106106
classobject *class;
107-
if (strcmp(name, "__dict__") == 0) {
108-
INCREF(op->cl_dict);
109-
return op->cl_dict;
110-
}
111-
if (strcmp(name, "__bases__") == 0) {
112-
INCREF(op->cl_bases);
113-
return op->cl_bases;
114-
}
115-
if (strcmp(name, "__name__") == 0) {
116-
if (op->cl_name == NULL)
117-
v = None;
118-
else
119-
v = op->cl_name;
120-
INCREF(v);
121-
return v;
107+
if (name[0] == '_' && name[1] == '_') {
108+
if (strcmp(name, "__dict__") == 0) {
109+
INCREF(op->cl_dict);
110+
return op->cl_dict;
111+
}
112+
if (strcmp(name, "__bases__") == 0) {
113+
INCREF(op->cl_bases);
114+
return op->cl_bases;
115+
}
116+
if (strcmp(name, "__name__") == 0) {
117+
if (op->cl_name == NULL)
118+
v = None;
119+
else
120+
v = op->cl_name;
121+
INCREF(v);
122+
return v;
123+
}
122124
}
123125
v = class_lookup(op, name, &class);
124126
if (v == NULL) {
@@ -280,11 +282,25 @@ newinstanceobject(class, arg)
280282
INCREF(class);
281283
inst->in_class = (classobject *)class;
282284
inst->in_dict = newdictobject();
285+
inst->in_getattr = NULL;
286+
inst->in_setattr = NULL;
287+
#ifdef WITH_THREAD
288+
inst->in_lock = NULL;
289+
inst->in_ident = 0;
290+
#endif
283291
if (inst->in_dict == NULL ||
284292
addaccess((classobject *)class, inst) != 0) {
285293
DECREF(inst);
286294
return NULL;
287295
}
296+
inst->in_setattr = instance_getattr(inst, "__setattr__");
297+
err_clear();
298+
inst->in_getattr = instance_getattr(inst, "__getattr__");
299+
err_clear();
300+
#ifdef WITH_THREAD
301+
if (inst->in_getattr != NULL)
302+
inst->in_lock = allocate_lock();
303+
#endif
288304
init = instance_getattr(inst, "__init__");
289305
if (init == NULL) {
290306
err_clear();
@@ -345,6 +361,12 @@ instance_dealloc(inst)
345361
return; /* __del__ added a reference; don't delete now */
346362
DECREF(inst->in_class);
347363
XDECREF(inst->in_dict);
364+
XDECREF(inst->in_getattr);
365+
XDECREF(inst->in_setattr);
366+
#ifdef WITH_THREAD
367+
if (inst->in_lock != NULL)
368+
free_lock(inst->in_lock);
369+
#endif
348370
free((ANY *)inst);
349371
}
350372

@@ -370,6 +392,32 @@ instance_getattr(inst, name)
370392
if (v == NULL) {
371393
v = class_lookup(inst->in_class, name, &class);
372394
if (v == NULL) {
395+
object *func;
396+
long ident;
397+
if ((func = inst->in_getattr) != NULL &&
398+
inst->in_ident != (ident = get_thread_ident())) {
399+
object *args;
400+
#ifdef WITH_THREAD
401+
type_lock lock = inst->in_lock;
402+
if (lock != NULL) {
403+
BGN_SAVE
404+
acquire_lock(lock, 0);
405+
END_SAVE
406+
}
407+
#endif
408+
inst->in_ident = ident;
409+
args = mkvalue("(s)", name);
410+
if (args != NULL) {
411+
v = call_object(func, args);
412+
DECREF(args);
413+
}
414+
inst->in_ident = 0;
415+
#ifdef WITH_THREAD
416+
if (lock != NULL)
417+
release_lock(lock);
418+
#endif
419+
return v;
420+
}
373421
err_setstr(AttributeError, name);
374422
return NULL;
375423
}
@@ -410,6 +458,18 @@ instance_setattr(inst, name, v)
410458
object *v;
411459
{
412460
object *ac;
461+
if (inst->in_setattr != NULL) {
462+
object *args = mkvalue("(sO)", name, v);
463+
if (args != NULL) {
464+
object *res = call_object(inst->in_setattr, args);
465+
DECREF(args);
466+
if (res != NULL) {
467+
DECREF(res);
468+
return 0;
469+
}
470+
}
471+
return -1;
472+
}
413473
if (name[0] == '_' && name[1] == '_') {
414474
int n = strlen(name);
415475
if (name[n-1] == '_' && name[n-2] == '_') {
@@ -824,11 +884,33 @@ BINARY(instance_mul, "__mul__")
824884
BINARY(instance_div, "__div__")
825885
BINARY(instance_mod, "__mod__")
826886
BINARY(instance_divmod, "__divmod__")
827-
BINARY(instance_pow, "__pow__")
828887
UNARY(instance_neg, "__neg__")
829888
UNARY(instance_pos, "__pos__")
830889
UNARY(instance_abs, "__abs__")
831890

891+
static object *
892+
instance_pow(self, other, modulus)
893+
instanceobject *self;
894+
object *other, *modulus;
895+
{
896+
object *func, *arg, *res;
897+
898+
if ((func = instance_getattr(self, "__pow__")) == NULL)
899+
return NULL;
900+
if (modulus == None)
901+
arg = mkvalue("O", other);
902+
else
903+
arg = mkvalue("(OO)", other, modulus);
904+
if (arg == NULL) {
905+
DECREF(func);
906+
return NULL;
907+
}
908+
res = call_object(func, arg);
909+
DECREF(func);
910+
DECREF(arg);
911+
return res;
912+
}
913+
832914
static int
833915
instance_nonzero(self)
834916
instanceobject *self;
@@ -922,7 +1004,7 @@ static number_methods instance_as_number = {
9221004
(binaryfunc)instance_div, /*nb_divide*/
9231005
(binaryfunc)instance_mod, /*nb_remainder*/
9241006
(binaryfunc)instance_divmod, /*nb_divmod*/
925-
(binaryfunc)instance_pow, /*nb_power*/
1007+
(ternaryfunc)instance_pow, /*nb_power*/
9261008
(unaryfunc)instance_neg, /*nb_negative*/
9271009
(unaryfunc)instance_pos, /*nb_positive*/
9281010
(unaryfunc)instance_abs, /*nb_absolute*/

0 commit comments

Comments
 (0)