Index: Objects/descrobject.c =================================================================== --- Objects/descrobject.c (revision 58892) +++ Objects/descrobject.c (working copy) @@ -1099,7 +1099,66 @@ {0} }; +PyDoc_STRVAR(getter_doc, + "Descriptor to change the setter on a property."); +PyObject * +property_getter(PyObject *self, PyObject *getter) +{ + Py_XDECREF(((propertyobject *)self)->prop_get); + if (getter == Py_None) + getter = NULL; + Py_XINCREF(getter); + ((propertyobject *)self)->prop_get = getter; + Py_INCREF(self); + return self; +} + +PyDoc_STRVAR(setter_doc, + "Descriptor to change the setter on a property.\n" + "This also sets the deleter if it hasn't been set before."); + +PyObject * +property_setter(PyObject *self, PyObject *setter) +{ + Py_XDECREF(((propertyobject *)self)->prop_set); + if (setter == Py_None) + setter = NULL; + Py_XINCREF(setter); + ((propertyobject *)self)->prop_set = setter; + if (((propertyobject *)self)->prop_del == NULL && setter != NULL) { + Py_INCREF(setter); + ((propertyobject *)self)->prop_del = setter; + } + Py_INCREF(self); + return self; +} + +PyDoc_STRVAR(deleter_doc, + "Descriptor to change the deleter on a property."); + +PyObject * +property_deleter(PyObject *self, PyObject *deleter) +{ + Py_XDECREF(((propertyobject *)self)->prop_del); + if (deleter == Py_None) + deleter = NULL; + Py_XINCREF(deleter); + ((propertyobject *)self)->prop_del = deleter; + Py_INCREF(self); + return self; +} + + + +static PyMethodDef property_methods[] = { + {"getter", property_getter, METH_O, getter_doc}, + {"setter", property_setter, METH_O, setter_doc}, + {"deleter", property_deleter, METH_O, deleter_doc}, + {0} +}; + + static void property_dealloc(PyObject *self) { @@ -1251,7 +1310,7 @@ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ + property_methods, /* tp_methods */ property_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ Index: Lib/test/test_descr.py =================================================================== --- Lib/test/test_descr.py (revision 58892) +++ Lib/test/test_descr.py (working copy) @@ -1984,6 +1984,43 @@ p = property(_testcapi.test_with_docstring) +def properties_more(): + class C: + foo = property(doc="hello") + + @foo.getter + def foo(self): + return self._foo + + @foo.setter + def foo(self, value=None): + if value is None: + del self._foo + else: + self._foo = abs(value) + + c = C() + assert C.foo.__doc__ == "hello" + assert not hasattr(c, "foo") + c.foo = -42 + assert c.foo == 42 + del c.foo + assert not hasattr(c, "foo") + + class D(C): + @C.foo.deleter + def foo(self): + try: + del self._foo + except AttributeError: + pass + + d = D() + d.foo = 24 + del d.foo + del d.foo + + def supers(): if verbose: print("Testing super...")