[Python-Dev] new property factory arguments

john coppola john_coppola_r_s@yahoo.com
Mon, 18 Feb 2002 00:41:06 -0800 (PST)


--0-1827853335-1014021666=:25719
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

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
--0-1827853335-1014021666=:25719
Content-Type: text/plain; name="descrobject.diff"
Content-Description: descrobject.diff
Content-Disposition: inline; filename="descrobject.diff"

*** 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)

--0-1827853335-1014021666=:25719
Content-Type: text/plain; name="TESTPROP.PY"
Content-Description: TESTPROP.PY
Content-Disposition: inline; filename="TESTPROP.PY"

__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

--0-1827853335-1014021666=:25719--