property syntax

B

bearophileHUGS

Probably you have already discussed this topic, but maybe you can
stand touching it again briefly.
Maybe properties aren't used so often to deserve a specific syntax,
but I don't like their syntax much. Here I show some alternative
solutions that work with the current Python, followed by a syntax
idea, that may be better fit for Python 3.0 (but maybe changing its
name it can be retrofitted into Python 2.6 too).

Some code is from:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/410698
That I have modified to suit my tastes.


# The first version doesn't work with Psyco:
# import psyco; psyco.full()

import sys

def nestedproperty(function):
keys = '__get__', '__set__', '__del__'
func_locals = {'doc':function.__doc__}
def probe_function(frame, event, arg):
if event == 'return':
locals = frame.f_locals
func_locals.update(dict((k, locals.get(k)) for k in keys))
sys.settrace(None)
return probe_function
sys.settrace(probe_function)
function()
return property(fget=func_locals.get("__get__"),
fset=func_locals.get("__set__"),
fdel=func_locals.get("__del__"),
doc=func_locals.get("doc")
)


class Angle(object):
def __init__(self, rad):
self._rad = rad

@nestedproperty
def rad():
"The angle in radians"
def __get__(self):
return self._rad
def __set__(self, angle):
if isinstance(angle, Angle):
angle = angle.rad
self._rad = float(angle)

a = Angle(5)
print a.rad
a.rad = 10
print a.rad
help(a)

# =====================================================

# The second version is cleaner, but at the moment it has a problem
with the property docstring (but that may be fixed) (it works with
Psyco):

class classpropertytype(property):
"Pythonic property syntax."
# Code from:
# www.z3lab.org/sections/blogs/philipp-weitershausen/2006_05_29_pycon-06-lightning-talk/
def __init__(self, name, bases=(), members=None):
if members is None:
members = {}
doc = members.get('__doc__')
if doc is None:
doc = members.get('__get__').__doc__
sup = super(classpropertytype, self)
return sup.__init__(members.get('__get__'),
members.get('__set__'),
members.get('__del__'),
doc)
classproperty = classpropertytype('classproperty')

class Angle(object):
def __init__(self, rad):
self._rad = rad

class rad(classproperty):
"The angle in radians"
def __get__(self):
return self._rad
def __set__(self,angle):
if isinstance(angle, Angle):
angle = angle.rad
self._rad = angle

a = Angle(5)
print a.rad
a.rad = 10
print a.rad
help(a)

# =====================================================

# The third way has a bit of magic, but I like it best, and it works
with Psyco too:

class _property_meta(type):
def __new__(meta, class_name, bases, new_attrs):
if bases == (object,):
# The property class itself
return type.__new__(meta,class_name,bases,new_attrs)
keys = "fget fset fdel __doc__".split()
return property(*(new_attrs.get(k) for k in keys))

class classproperty(object):
__metaclass__ = _property_meta

def __new__(cls, fget=None, fset=None, fdel=None, fdoc=None):
if fdoc is None and fget is not None:
fdoc = fget.__doc__
return property(fget, fset, fdel, fdoc)


class Angle(object):
def __init__(self, rad):
self._rad = rad

class rad(classproperty):
"The angle in radians"
def fget(self):
return self._rad
def fset(self,angle):
if isinstance(angle, Angle):
angle = angle.rad
self._rad = angle


a = Angle(5)
print a.rad
a.rad = 10
print a.rad
help(a)


# =====================================================

# I may appreciate a better syntax, this is just an idea:
# (George Sakkis has suggested a different syntax that I like less)

"""

class Angle(object):
def __init__(self,rad):
self._rad = rad

property rad:
"The angle in radians"
def __get__(self):
return self._rad
def __set__(self, angle):
if isinstance(angle, Angle):
angle = angle.rad
self._rad = angle

class Angle2(Angle):
property rad:
def __get__(self):
return self._rad * 2

"""

# I'd like that possible syntax to mean this:

class Angle(object):
def __init__(self, rad):
self._rad = rad

def get_rad(self):
return self._rad

def set_rad(self, angle):
if isinstance(angle, Angle):
angle = angle.rad
self._rad = angle

rad = property(fget=lambda self: self.get_rad(),
fset=lambda self, angle: self.set_rad(angle),
doc="The angle in radians"
)

class Angle2(Angle):
def get_rad(self):
return self._rad * 2

a = Angle(5)
print a.rad
a.rad = 10
print a.rad
help(a)

a = Angle2(5)
print a.rad
a.rad = 10
print a.rad
help(a)

Bye,
bearophile
 
G

Gabriel Genellina

Probably you have already discussed this topic, but maybe you can
stand touching it again briefly.
Maybe properties aren't used so often to deserve a specific syntax,
but I don't like their syntax much. Here I show some alternative
solutions that work with the current Python, followed by a syntax
idea, that may be better fit for Python 3.0 (but maybe changing its
name it can be retrofitted into Python 2.6 too).

You miss this common way, that does not depend on metaclasses, nor base
classes, nor custom decorators... The only drawback is the "deprecated"
status of apply:

class Angle(object):

@apply
def rad():
doc = "The angle in radians"
def fget(self):
return self._rad
def fset(self, value):
self._rad = value
return property(**locals())


(Hmmm... I wonder what the 2to3 conversion tool is doing in this case?)
 
B

bearophileHUGS

Gabriel Genellina:
You miss this common way, that does not depend on metaclasses,
nor base classes, nor custom decorators...

My purpose was to discuss a new syntax. The other stuff is mostly for
reference, to show that lot of (some) people has tried to find
alternative solutions to a problem they feel.

The only drawback is the "deprecated"

I can see other drawbacks: you have to use an explicit doc = "..."
instead of a normal docstring, and you have to remember to put return
property(**locals()) at its end. I don't know if your version is
compatible with Psyco (I presume it's compatible). And I think all
those solutions can't be subclassed like I have shown in the
altenative syntax (but maybe you can find a way to modify the
metaclass version to allow this too).

Bye and thank you,
bearophile
 
G

Gabriel Genellina

Gabriel Genellina:

My purpose was to discuss a new syntax. The other stuff is mostly for
reference, to show that lot of (some) people has tried to find
alternative solutions to a problem they feel.

Nex syntax has many disadvantages, so you should come with a greater
analysis of what would be the gain.
Maybe these comments are applicable here:
http://mail.python.org/pipermail/python-dev/2007-February/071061.html and
http://mail.python.org/pipermail/python-dev/2007-February/071123.html
(sorry, a long thread, and two subject lines, that's why I had to post two
references)
I think this thread belongs to python-ideas instead.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top