]> granicus.if.org Git - python/commitdiff
Issue 1416. Add getter, setter, deleter methods to properties that can be
authorGuido van Rossum <guido@python.org>
Sat, 10 Nov 2007 22:12:24 +0000 (22:12 +0000)
committerGuido van Rossum <guido@python.org>
Sat, 10 Nov 2007 22:12:24 +0000 (22:12 +0000)
used as decorators to create fully-populated properties.

Lib/test/test_descr.py
Objects/descrobject.c

index 9a45cf1760b75c9d2d68734fe94b014e358025e6..0c06d9a99cdc782ff3c9bb435c4bed7dee6423db 100644 (file)
@@ -2131,6 +2131,71 @@ def properties():
             p = property(_testcapi.test_with_docstring)
 
 
+def properties_plus():
+    class C:
+        foo = property(doc="hello")
+        @foo.getter
+        def foo(self):
+            return self._foo
+        @foo.setter
+        def foo(self, value):
+            self._foo = abs(value)
+        @foo.deleter
+        def foo(self):
+            del self._foo
+    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
+    assert d.foo == 24
+    del d.foo
+    del d.foo
+
+    class E:
+        @property
+        def foo(self):
+            return self._foo
+        @foo.setter
+        def foo (self, value):
+            raise RuntimeError
+        @foo.setter
+        @foo.deleter
+        def foo(self, value=None):
+            if value is None:
+                del self._foo
+            else:
+                self._foo = abs(value)
+    e = E()
+    e.foo = -42
+    assert e.foo == 42
+    del e.foo
+
+    class F(E):
+        @E.foo.deleter
+        def foo(self):
+            del self._foo
+        @foo.setter
+        def foo(self, value):
+            self._foo = max(0, value)
+    f = F()
+    f.foo = -10
+    assert f.foo == 0
+    del f.foo
+
+
 def supers():
     if verbose: print "Testing super..."
 
index ec9faa5e06dc347e3613134e6be7ea8cb8f97030..535a49f170f1e1133c13b13d011b764f77e59bcb 100644 (file)
@@ -1108,6 +1108,60 @@ static PyMemberDef property_members[] = {
        {0}
 };
 
+PyDoc_STRVAR(getter_doc,
+            "Descriptor to change the getter 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");
+
+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;
+       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)
@@ -1260,7 +1314,7 @@ PyTypeObject PyProperty_Type = {
        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 */