new property factory arguments
Hello python developers. After discussions with Fred about defining how property objects are created, I decided to give it a whirl myself. After about minute of piddling, I came up with something I thought would be a hack but is quite interesting. Ultimately, this is what I came up with. class Foo(object): def __get__(self, container): print "this is get" print "self:", type(self) print "container:", type(container) print def __set__(self, container, value): print "this is set" print "self:", type(self) print "container:", type(container) print "value:", value print def __del__(self, container): print "this is del" print "self:", type(self) print "container:", type(container) print class Spam(object): x=property(Foo()) I feel this has the benefit of encapsulating the x property from the Spam object. If coupling is needed, then access to Spam can be obtained via container. This was the interesting hack I was talking about. I first tried it without container and got an error, but then I decided to see what that second argument was like hummm, interesting and I liked it. What's really cool is that Foo can be used by a completely separate class. Perhaps Foo is a singleton for a DB connection. A single connection could be created in __new__, and other attribute details created in __init__. So class Spam is decoupled from what is going on in Foo. Whereas the former syntax, this was not possible. I've attached a descrobject.diff file to this email as well as testprop.py. (I've never tried sending an attachment to python-dev, I hope it works.) Enjoy, John Coppola __________________________________________________ Do You Yahoo!? Yahoo! Sports - Coverage of the 2002 Olympic Games http://sports.yahoo.com *** PythonOrig/Python-2.2/Objects/descrobject.c Sat Dec 15 00:00:30 2001 --- PythonDev/Python-2.2/Objects/descrobject.c Sun Feb 17 21:52:55 2002 *************** *** 1003,1024 **** } static int ! property_init(PyObject *self, PyObject *args, PyObject *kwds) { ! PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; ! static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; ! propertyobject *gs = (propertyobject *)self; ! ! if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", ! kwlist, &get, &set, &del, &doc)) ! return -1; ! ! if (get == Py_None) ! get = NULL; ! if (set == Py_None) ! set = NULL; ! if (del == Py_None) ! del = NULL; Py_XINCREF(get); Py_XINCREF(set); --- 1003,1023 ---- } static int ! property_init(PyObject *self, PyObject *args, PyObject *kw) { ! PyObject *get=NULL, *set=NULL, *del=NULL, *doc=NULL, *arg=NULL; ! static char *kwlist[] = {"object", 0}; ! propertyobject *gs = (propertyobject *)self; ! if (!PyArg_ParseTupleAndKeywords(args,kw,"|O:property",kwlist,&arg)) ! return -1; ! ! get = PyObject_GetAttrString(arg,"__get__"); ! set = PyObject_GetAttrString(arg,"__set__"); ! del = PyObject_GetAttrString(arg,"__del__"); ! doc = PyObject_GetAttrString(arg,"__doc__"); ! if (get == Py_None) get = NULL; ! if (set == Py_None) set = NULL; ! if (del == Py_None) del = NULL; Py_XINCREF(get); Py_XINCREF(set); *************** *** 1034,1049 **** } static char property_doc[] = ! "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n" "\n" ! "fget is a function to be used for getting an attribute value, and likewise\n" ! "fset is a function for setting, and fdel a function for del'ing, an\n" ! "attribute. Typical use is to define a managed attribute x:\n" "class C(object):\n" ! " def getx(self): return self.__x\n" ! " def setx(self, value): self.__x = value\n" ! " def delx(self): del self.__x\n" ! " x = property(getx, setx, delx, \"I'm the 'x' property.\")"; static int property_traverse(PyObject *self, visitproc visit, void *arg) --- 1033,1050 ---- } static char property_doc[] = ! "property(object) -> property attribute\n" "\n" ! "__get__ is a function to be used for getting an attribute value, and\n" ! "likewise __set__ is a function for setting, and __del__ a function for\n" ! "del'ing, an attribute. Typical use is to define a managed attribute x:\n" "class C(object):\n" ! " def __get__(self, container): return self.__x\n" ! " def __set__(self, container, value): self.__x = value\n" ! " def __del__(self, container): del self.__x\n" ! "\n" ! "class D(object):\n" ! " x = property(object=C(), \"I'm the 'x' property.\")"; static int property_traverse(PyObject *self, visitproc visit, void *arg) __doc__="""\ class Foo(object): def __get__(self, container): print "this is get" print "self:", type(self) print "container:", type(container) print def __set__(self, container, value): print "this is set" print "self:", type(self) print "container:", type(container) print "value:", value print def __del__(self, container): print "this is del" print "self:", type(self) print "container:", type(container) print __doc__ = "this is doc" """ exec __doc__ class Spam(object): x=property(Foo()) print __doc__ a=Spam() a.x=5 print "getting:", a.x del a.x
With minor changes, this works already. class Foo(property): def __get__(self, container, _type=None): print "this is get" print "self:", self print "container:", container print def __set__(self, container, value): print "this is set" print "self:", self print "container:", container print "value:", value print def __delete__(self, container): print "this is del" print "self:", type(self) print "container:", type(container) print class Spam(object): x = Foo() ## Jason Orendorff http://www.jorendorff.com/
--- Jason Orendorff <jason@jorendorff.com> wrote:
With minor changes, this works already.
class Foo(property): def __get__(self, container, _type=None): print "this is get" print "self:", self . . .
I didn't subclass from property? I do believe my with example, any object new or old could be used as a property. And by looking at the code, property_init clearly did not include GetAttr methods for __get__, __set__, __del__. If fact, there is not reason to include __delete__, why not use __del__ instead? If you send any ole python class instance to property your code fails. Thats the need for the change. Without my patch... class Bar(object): # <== object! def __get__(self,container,tp=None): print "get" def __set__(self,container,value): print "set" def __delete__(self,container): print "del"
class Foo(object): x=property(Bar()) #performs coersion
a=Foo() a.x
Fails! With my patch, it works. Infact, I feel very strongly, that the old syntax should be removed. Better now then later. property(fget,fset,fdel,fdoc) does not make much sense in the new object oriented world of python. Sincerely, John Coppola __________________________________________________ Do You Yahoo!? Yahoo! Sports - Coverage of the 2002 Olympic Games http://sports.yahoo.com
john coppola wrote:
Hello python developers. After discussions with Fred about defining how property objects are created, I decided to give it a whirl myself. After about minute of piddling, I came up with something I thought would be a hack but is quite interesting. ... ! property_init(PyObject *self, PyObject *args, PyObject *kwds) { ! PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; ! static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; ! propertyobject *gs = (propertyobject *)self; ! ! if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", ! kwlist, &get, &set, &del, &doc)) ! return -1; ... --- 1003,1023 ---- }
static int ! property_init(PyObject *self, PyObject *args, PyObject *kw) { ! PyObject *get=NULL, *set=NULL, *del=NULL, *doc=NULL, *arg=NULL; ! static char *kwlist[] = {"object", 0}; ! propertyobject *gs = (propertyobject *)self; ! if (!PyArg_ParseTupleAndKeywords(args,kw,"|O:property",kwlist,&arg)) ! return -1; ! ! get = PyObject_GetAttrString(arg,"__get__"); ! set = PyObject_GetAttrString(arg,"__set__"); ! del = PyObject_GetAttrString(arg,"__del__"); ! doc = PyObject_GetAttrString(arg,"__doc__");
Wouldn't this break the documented API ? If so, I'd suggest to provide a second constructor which exposes the new signature instead. Should be easy to do in Python... -- Marc-Andre Lemburg CEO eGenix.com Software GmbH ______________________________________________________________________ Company & Consulting: http://www.egenix.com/ Python Software: http://www.egenix.com/files/python/
participants (3)
-
Jason Orendorff -
john coppola -
M.-A. Lemburg