Kaydet (Commit) 5b443c62 authored tarafından Guido van Rossum's avatar Guido van Rossum

Address SF patch #480716 as well as related issues.

SF patch #480716 by Greg Chapman fixes the problem that super's
__get__ method always returns an instance of super, even when the
instance whose __get__ method is called is an instance of a subclass
of super.

Other issues fixed:

- super(C, C()).__class__ would return the __class__ attribute of C()
  rather than the __class__ attribute of the super object.  This is
  confusing.  To fix this, I decided to change the semantics of super
  so that it only applies to code attributes, not to data attributes.
  After all, overriding data attributes is not supported anyway.

- While super(C, x) carefully checked that x is an instance of C,
  super(C).__get__(x) made no such check, allowing for a loophole.
  This is now fixed.
üst 22f9c6dd
...@@ -1572,7 +1572,57 @@ def supers(): ...@@ -1572,7 +1572,57 @@ def supers():
def meth(self, a): def meth(self, a):
return "D(%r)" % a + super(D, self).meth(a) return "D(%r)" % a + super(D, self).meth(a)
verify (D().meth(4) == "D(4)C(4)B(4)A(4)") vereq(D().meth(4), "D(4)C(4)B(4)A(4)")
# Test for subclassing super
class mysuper(super):
def __init__(self, *args):
return super(mysuper, self).__init__(*args)
class E(D):
def meth(self, a):
return "E(%r)" % a + mysuper(E, self).meth(a)
vereq(E().meth(5), "E(5)D(5)C(5)B(5)A(5)")
class F(E):
def meth(self, a):
s = self.__super
return "F(%r)[%s]" % (a, s.__class__.__name__) + s.meth(a)
F._F__super = mysuper(F)
vereq(F().meth(6), "F(6)[mysuper]E(6)D(6)C(6)B(6)A(6)")
# Make sure certain errors are raised
try:
super(D, 42)
except TypeError:
pass
else:
raise TestFailed, "shouldn't allow super(D, 42)"
try:
super(D, C())
except TypeError:
pass
else:
raise TestFailed, "shouldn't allow super(D, C())"
try:
super(D).__get__(12)
except TypeError:
pass
else:
raise TestFailed, "shouldn't allow super(D).__get__(12)"
try:
super(D).__get__(C())
except TypeError:
pass
else:
raise TestFailed, "shouldn't allow super(D).__get__(C())"
def inherits(): def inherits():
if verbose: print "Testing inheritance from basic types..." if verbose: print "Testing inheritance from basic types..."
......
...@@ -3929,7 +3929,7 @@ super_getattro(PyObject *self, PyObject *name) ...@@ -3929,7 +3929,7 @@ super_getattro(PyObject *self, PyObject *name)
else else
continue; continue;
res = PyDict_GetItem(dict, name); res = PyDict_GetItem(dict, name);
if (res != NULL) { if (res != NULL && !PyDescr_IsData(res)) {
Py_INCREF(res); Py_INCREF(res);
f = res->ob_type->tp_descr_get; f = res->ob_type->tp_descr_get;
if (f != NULL) { if (f != NULL) {
...@@ -3944,6 +3944,21 @@ super_getattro(PyObject *self, PyObject *name) ...@@ -3944,6 +3944,21 @@ super_getattro(PyObject *self, PyObject *name)
return PyObject_GenericGetAttr(self, name); return PyObject_GenericGetAttr(self, name);
} }
static int
supercheck(PyTypeObject *type, PyObject *obj)
{
if (!PyType_IsSubtype(obj->ob_type, type) &&
!(PyType_Check(obj) &&
PyType_IsSubtype((PyTypeObject *)obj, type))) {
PyErr_SetString(PyExc_TypeError,
"super(type, obj): "
"obj must be an instance or subtype of type");
return -1;
}
else
return 0;
}
static PyObject * static PyObject *
super_descr_get(PyObject *self, PyObject *obj, PyObject *type) super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
{ {
...@@ -3955,14 +3970,25 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type) ...@@ -3955,14 +3970,25 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
Py_INCREF(self); Py_INCREF(self);
return self; return self;
} }
new = (superobject *)PySuper_Type.tp_new(&PySuper_Type, NULL, NULL); if (su->ob_type != &PySuper_Type)
if (new == NULL) /* If su is an instance of a subclass of super,
return NULL; call its type */
Py_INCREF(su->type); return PyObject_CallFunction((PyObject *)su->ob_type,
Py_INCREF(obj); "OO", su->type, obj);
new->type = su->type; else {
new->obj = obj; /* Inline the common case */
return (PyObject *)new; if (supercheck(su->type, obj) < 0)
return NULL;
new = (superobject *)PySuper_Type.tp_new(&PySuper_Type,
NULL, NULL);
if (new == NULL)
return NULL;
Py_INCREF(su->type);
Py_INCREF(obj);
new->type = su->type;
new->obj = obj;
return (PyObject *)new;
}
} }
static int static int
...@@ -3976,15 +4002,8 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -3976,15 +4002,8 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
return -1; return -1;
if (obj == Py_None) if (obj == Py_None)
obj = NULL; obj = NULL;
if (obj != NULL && if (obj != NULL && supercheck(type, obj) < 0)
!PyType_IsSubtype(obj->ob_type, type) &&
!(PyType_Check(obj) &&
PyType_IsSubtype((PyTypeObject *)obj, type))) {
PyErr_SetString(PyExc_TypeError,
"super(type, obj): "
"obj must be an instance or subtype of type");
return -1; return -1;
}
Py_INCREF(type); Py_INCREF(type);
Py_XINCREF(obj); Py_XINCREF(obj);
su->type = type; su->type = type;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment