diff options
author | Guido van Rossum <guido@python.org> | 2001-09-21 21:24:49 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2001-09-21 21:24:49 (GMT) |
commit | 19c1cd5b352e503c4585398d2533e5ae3bf4c189 (patch) | |
tree | 4749110a9fdd7d5ac0c249b8d3d860676524d81e | |
parent | 56dd35bd44684d6d03db6fdfb2055898f0ef0b91 (diff) | |
download | cpython-19c1cd5b352e503c4585398d2533e5ae3bf4c189.zip cpython-19c1cd5b352e503c4585398d2533e5ae3bf4c189.tar.gz cpython-19c1cd5b352e503c4585398d2533e5ae3bf4c189.tar.bz2 |
Add the __getattr__ hook back. The rules are now:
- if __getattribute__ exists, it is called first;
if it doesn't exists, PyObject_GenericGetAttr is called first.
- if the above raises AttributeError, and __getattr__ exists,
it is called.
-rw-r--r-- | Lib/test/test_descr.py | 9 | ||||
-rw-r--r-- | Objects/typeobject.c | 39 |
2 files changed, 43 insertions, 5 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index bbd4372..2f540af 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -880,9 +880,8 @@ def dynamics(): def mygetattr(self, name): if name == "spam": return "spam" - else: - return object.__getattribute__(self, name) - C.__getattribute__ = mygetattr + raise AttributeError + C.__getattr__ = mygetattr verify(a.spam == "spam") a.new = 12 verify(a.new == 12) @@ -1105,11 +1104,11 @@ def overloading(): class C(B): - def __getattribute__(self, name): + def __getattr__(self, name): if name == "foo": return ("getattr", name) else: - return B.__getattribute__(self, name) + raise AttributeError def __setattr__(self, name, value): if name == "foo": self.setattr = (name, value) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5f8fd01..1842f3c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2891,6 +2891,44 @@ slot_tp_getattro(PyObject *self, PyObject *name) return PyObject_CallFunction(getattr, "OO", self, name); } +static PyObject * +slot_tp_getattr_hook(PyObject *self, PyObject *name) +{ + PyTypeObject *tp = self->ob_type; + PyObject *getattr, *getattribute, *res; + static PyObject *getattribute_str = NULL; + static PyObject *getattr_str = NULL; + + if (getattr_str == NULL) { + getattr_str = PyString_InternFromString("__getattr__"); + if (getattr_str == NULL) + return NULL; + } + if (getattribute_str == NULL) { + getattribute_str = + PyString_InternFromString("__getattribute__"); + if (getattribute_str == NULL) + return NULL; + } + getattr = _PyType_Lookup(tp, getattr_str); + getattribute = _PyType_Lookup(tp, getattribute_str); + if (getattr == NULL && getattribute == NULL) { + /* Avoid further slowdowns */ + if (tp->tp_getattro == slot_tp_getattr_hook) + tp->tp_getattro = PyObject_GenericGetAttr; + return PyObject_GenericGetAttr(self, name); + } + if (getattribute == NULL) + res = PyObject_GenericGetAttr(self, name); + else + res = PyObject_CallFunction(getattribute, "OO", self, name); + if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + res = PyObject_CallFunction(getattr, "OO", self, name); + } + return res; +} + static int slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value) { @@ -3197,6 +3235,7 @@ override_slots(PyTypeObject *type, PyObject *dict) TPSLOT("__call__", tp_call, slot_tp_call); TPSLOT("__str__", tp_str, slot_tp_str); TPSLOT("__getattribute__", tp_getattro, slot_tp_getattro); + TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook); TPSLOT("__setattr__", tp_setattro, slot_tp_setattro); TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare); TPSLOT("__le__", tp_richcompare, slot_tp_richcompare); |