mirror of
https://github.com/python/cpython.git
synced 2025-11-01 18:51:43 +00:00
Implement another useful feature for proxies: in super(X, x), x may
now be a proxy for an X instance, as long as issubclass(x.__class__, X).
This commit is contained in:
parent
e5b130bcdb
commit
a89d10edc9
3 changed files with 125 additions and 17 deletions
|
|
@ -3791,6 +3791,13 @@ def isinst_isclass():
|
|||
pa = Proxy(a)
|
||||
verify(isinstance(a, C)) # Baseline
|
||||
verify(isinstance(pa, C)) # Test
|
||||
# Test with a classic subclass
|
||||
class D(C):
|
||||
pass
|
||||
a = D()
|
||||
pa = Proxy(a)
|
||||
verify(isinstance(a, C)) # Baseline
|
||||
verify(isinstance(pa, C)) # Test
|
||||
# Test with a new-style class
|
||||
class C(object):
|
||||
pass
|
||||
|
|
@ -3798,6 +3805,37 @@ def isinst_isclass():
|
|||
pa = Proxy(a)
|
||||
verify(isinstance(a, C)) # Baseline
|
||||
verify(isinstance(pa, C)) # Test
|
||||
# Test with a new-style subclass
|
||||
class D(C):
|
||||
pass
|
||||
a = D()
|
||||
pa = Proxy(a)
|
||||
verify(isinstance(a, C)) # Baseline
|
||||
verify(isinstance(pa, C)) # Test
|
||||
|
||||
def proxysuper():
|
||||
if verbose:
|
||||
print "Testing super() for a proxy object..."
|
||||
class Proxy(object):
|
||||
def __init__(self, obj):
|
||||
self.__obj = obj
|
||||
def __getattribute__(self, name):
|
||||
if name.startswith("_Proxy__"):
|
||||
return object.__getattribute__(self, name)
|
||||
else:
|
||||
return getattr(self.__obj, name)
|
||||
|
||||
class B(object):
|
||||
def f(self):
|
||||
return "B.f"
|
||||
|
||||
class C(B):
|
||||
def f(self):
|
||||
return super(C, self).f() + "->C.f"
|
||||
|
||||
obj = C()
|
||||
p = Proxy(obj)
|
||||
vereq(C.__dict__["f"](p), "B.f->C.f")
|
||||
|
||||
|
||||
def test_main():
|
||||
|
|
@ -3887,6 +3925,7 @@ def test_main():
|
|||
dict_type_with_metaclass()
|
||||
meth_class_get()
|
||||
isinst_isclass()
|
||||
proxysuper()
|
||||
|
||||
if verbose: print "All OK"
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ What's New in Python 2.3 alpha 2?
|
|||
Core and builtins
|
||||
-----------------
|
||||
|
||||
- super(X, x): x may now be a proxy for an X instance, i.e.
|
||||
issubclass(x.__class__, X) but not issubclass(type(x), X).
|
||||
|
||||
- isinstance(x, X): if X is a new-style class, this is now equivalent
|
||||
to issubclass(type(x), X) or issubclass(x.__class__, X). Previously
|
||||
only type(x) was tested. (For classic classes this was already the
|
||||
|
|
|
|||
|
|
@ -5025,6 +5025,7 @@ typedef struct {
|
|||
PyObject_HEAD
|
||||
PyTypeObject *type;
|
||||
PyObject *obj;
|
||||
PyTypeObject *obj_type;
|
||||
} superobject;
|
||||
|
||||
static PyMemberDef super_members[] = {
|
||||
|
|
@ -5032,6 +5033,8 @@ static PyMemberDef super_members[] = {
|
|||
"the class invoking super()"},
|
||||
{"__self__", T_OBJECT, offsetof(superobject, obj), READONLY,
|
||||
"the instance invoking super(); may be None"},
|
||||
{"__self_class__", T_OBJECT, offsetof(superobject, obj_type), READONLY,
|
||||
"the type of the the instance invoking super(); may be None"},
|
||||
{0}
|
||||
};
|
||||
|
||||
|
|
@ -5043,6 +5046,7 @@ super_dealloc(PyObject *self)
|
|||
_PyObject_GC_UNTRACK(self);
|
||||
Py_XDECREF(su->obj);
|
||||
Py_XDECREF(su->type);
|
||||
Py_XDECREF(su->obj_type);
|
||||
self->ob_type->tp_free(self);
|
||||
}
|
||||
|
||||
|
|
@ -5051,11 +5055,11 @@ super_repr(PyObject *self)
|
|||
{
|
||||
superobject *su = (superobject *)self;
|
||||
|
||||
if (su->obj)
|
||||
if (su->obj_type)
|
||||
return PyString_FromFormat(
|
||||
"<super: <class '%s'>, <%s object>>",
|
||||
su->type ? su->type->tp_name : "NULL",
|
||||
su->obj->ob_type->tp_name);
|
||||
su->obj_type->tp_name);
|
||||
else
|
||||
return PyString_FromFormat(
|
||||
"<super: <class '%s'>, NULL>",
|
||||
|
|
@ -5067,13 +5071,13 @@ super_getattro(PyObject *self, PyObject *name)
|
|||
{
|
||||
superobject *su = (superobject *)self;
|
||||
|
||||
if (su->obj != NULL) {
|
||||
if (su->obj_type != NULL) {
|
||||
PyObject *mro, *res, *tmp, *dict;
|
||||
PyTypeObject *starttype;
|
||||
descrgetfunc f;
|
||||
int i, n;
|
||||
|
||||
starttype = su->obj->ob_type;
|
||||
starttype = su->obj_type;
|
||||
mro = starttype->tp_mro;
|
||||
|
||||
if (mro == NULL)
|
||||
|
|
@ -5086,6 +5090,7 @@ super_getattro(PyObject *self, PyObject *name)
|
|||
if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i))
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
if (i >= n && PyType_Check(su->obj)) {
|
||||
starttype = (PyTypeObject *)(su->obj);
|
||||
mro = starttype->tp_mro;
|
||||
|
|
@ -5101,6 +5106,7 @@ super_getattro(PyObject *self, PyObject *name)
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
i++;
|
||||
res = NULL;
|
||||
for (; i < n; i++) {
|
||||
|
|
@ -5128,19 +5134,71 @@ super_getattro(PyObject *self, PyObject *name)
|
|||
return PyObject_GenericGetAttr(self, name);
|
||||
}
|
||||
|
||||
static int
|
||||
static PyTypeObject *
|
||||
supercheck(PyTypeObject *type, PyObject *obj)
|
||||
{
|
||||
if (!PyType_IsSubtype(obj->ob_type, type) &&
|
||||
!(PyType_Check(obj) &&
|
||||
PyType_IsSubtype((PyTypeObject *)obj, type))) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
/* Check that a super() call makes sense. Return a type object.
|
||||
|
||||
obj can be a new-style class, or an instance of one:
|
||||
|
||||
- If it is a class, it must be a subclass of 'type'. This case is
|
||||
used for class methods; the return value is obj.
|
||||
|
||||
- If it is an instance, it must be an instance of 'type'. This is
|
||||
the normal case; the return value is obj.__class__.
|
||||
|
||||
But... when obj is an instance, we want to allow for the case where
|
||||
obj->ob_type is not a subclass of type, but obj.__class__ is!
|
||||
This will allow using super() with a proxy for obj.
|
||||
*/
|
||||
|
||||
if (PyType_Check(obj)) {
|
||||
/* It's a new-style class */
|
||||
if (PyType_IsSubtype((PyTypeObject *)obj, type)) {
|
||||
Py_INCREF(obj);
|
||||
return (PyTypeObject *)obj;
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
}
|
||||
else if (PyType_IsSubtype(obj->ob_type, type)) {
|
||||
Py_INCREF(obj->ob_type);
|
||||
return obj->ob_type;
|
||||
}
|
||||
else {
|
||||
/* Try the slow way */
|
||||
static PyObject *class_str = NULL;
|
||||
PyObject *class_attr;
|
||||
|
||||
if (class_str == NULL) {
|
||||
class_str = PyString_FromString("__class__");
|
||||
if (class_str == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
class_attr = PyObject_GetAttr(obj, class_str);
|
||||
|
||||
if (class_attr != NULL &&
|
||||
PyType_Check(class_attr) &&
|
||||
(PyTypeObject *)class_attr != obj->ob_type)
|
||||
{
|
||||
int ok = PyType_IsSubtype(
|
||||
(PyTypeObject *)class_attr, type);
|
||||
if (ok)
|
||||
return (PyTypeObject *)class_attr;
|
||||
}
|
||||
|
||||
if (class_attr == NULL)
|
||||
PyErr_Clear();
|
||||
else
|
||||
Py_DECREF(class_attr);
|
||||
}
|
||||
|
||||
fail:
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"super(type, obj): "
|
||||
"obj must be an instance or subtype of type");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
|
@ -5161,7 +5219,8 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
|||
"OO", su->type, obj);
|
||||
else {
|
||||
/* Inline the common case */
|
||||
if (supercheck(su->type, obj) < 0)
|
||||
PyTypeObject *obj_type = supercheck(su->type, obj);
|
||||
if (obj_type == NULL)
|
||||
return NULL;
|
||||
new = (superobject *)PySuper_Type.tp_new(&PySuper_Type,
|
||||
NULL, NULL);
|
||||
|
|
@ -5171,6 +5230,7 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
|||
Py_INCREF(obj);
|
||||
new->type = su->type;
|
||||
new->obj = obj;
|
||||
new->obj_type = obj_type;
|
||||
return (PyObject *)new;
|
||||
}
|
||||
}
|
||||
|
|
@ -5181,17 +5241,22 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
superobject *su = (superobject *)self;
|
||||
PyTypeObject *type;
|
||||
PyObject *obj = NULL;
|
||||
PyTypeObject *obj_type = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!|O:super", &PyType_Type, &type, &obj))
|
||||
return -1;
|
||||
if (obj == Py_None)
|
||||
obj = NULL;
|
||||
if (obj != NULL && supercheck(type, obj) < 0)
|
||||
return -1;
|
||||
if (obj != NULL) {
|
||||
obj_type = supercheck(type, obj);
|
||||
if (obj_type == NULL)
|
||||
return -1;
|
||||
Py_INCREF(obj);
|
||||
}
|
||||
Py_INCREF(type);
|
||||
Py_XINCREF(obj);
|
||||
su->type = type;
|
||||
su->obj = obj;
|
||||
su->obj_type = obj_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -5219,6 +5284,7 @@ super_traverse(PyObject *self, visitproc visit, void *arg)
|
|||
|
||||
VISIT(su->obj);
|
||||
VISIT(su->type);
|
||||
VISIT(su->obj_type);
|
||||
|
||||
#undef VISIT
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue