included rwproperty stuff in util.property

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1602 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-03-01 08:46:45 +00:00
parent b4dd7ccddd
commit 53ae9f332a
2 changed files with 177 additions and 3 deletions

View file

@ -17,9 +17,11 @@
# #
""" """
Advanced properties, esp the lazy one... Advanced properties, i.e. the lazy one and Philipp von Weitershausen's
read & write properties.
Based on zope.cachedescriptors.property.Lazy Based on zope.cachedescriptors.property.Lazy and including code from
http://cheeseshop.python.org/pypi/rwproperty.
$Id$ $Id$
""" """
@ -39,3 +41,76 @@ class lzprop(object):
value = self.func(inst) value = self.func(inst)
inst.__dict__[self.func.__name__] = value inst.__dict__[self.func.__name__] = value
return value return value
# Read & write properties
#
# Copyright (c) 2006 by Philipp "philiKON" von Weitershausen
# philikon@philikon.de
#
# Freely distributable under the terms of the Zope Public License, v2.1.
#
# See rwproperty.txt for detailed explanations
#
import sys
__all__ = ['getproperty', 'setproperty', 'delproperty']
class rwproperty(object):
def __new__(cls, func):
name = func.__name__
# ugly, but common hack
frame = sys._getframe(1)
locals = frame.f_locals
if name not in locals:
return cls.createProperty(func)
oldprop = locals[name]
if isinstance(oldprop, property):
return cls.enhanceProperty(oldprop, func)
raise TypeError("read & write properties cannot be mixed with "
"other attributes except regular property objects.")
# this might not be particularly elegant, but it's easy on the eyes
@staticmethod
def createProperty(func):
raise NotImplementedError
@staticmethod
def enhanceProperty(oldprop, func):
raise NotImplementedError
class getproperty(rwproperty):
@staticmethod
def createProperty(func):
return property(func)
@staticmethod
def enhanceProperty(oldprop, func):
return property(func, oldprop.fset, oldprop.fdel)
class setproperty(rwproperty):
@staticmethod
def createProperty(func):
return property(None, func)
@staticmethod
def enhanceProperty(oldprop, func):
return property(oldprop.fget, func, oldprop.fdel)
class delproperty(rwproperty):
@staticmethod
def createProperty(func):
return property(None, None, func)
@staticmethod
def enhanceProperty(oldprop, func):
return property(oldprop.fget, oldprop.fset, func)

View file

@ -7,7 +7,7 @@ $Id$
lzprop lzprop
====== ======
The `lzprop` decorator allows the declaration of lazy properties - attributes The ``@lzprop`` decorator allows the declaration of lazy properties - attributes
that are calculated only on first access, and then just once. This is that are calculated only on first access, and then just once. This is
extremely useful when working with objects of a limited lifetime (e.g. extremely useful when working with objects of a limited lifetime (e.g.
adapters) that provide results from expensive calculations. adapters) that provide results from expensive calculations.
@ -52,3 +52,102 @@ already during compilation or object creation):
>>> demo2.value >>> demo2.value
105 105
rwproperty
==========
:Author: Philipp von Weitershausen
:Email: philikon@philikon.de
:License: Zope Public License, v2.1
Goal
----
There should be a way to declare a read & write property and still use
the compact and easy decorator spelling. The read & write properties
should be as easy to use as the read-only property. We explicitly
don't want that immediately called function that really just helps us
name the attribute and create a local scope for the getter and setter.
Read & write property
---------------------
Read & write properties work like regular properties. You simply
define a method and then apply a decorator, except that you now don't
use ``@property`` but ``@getproperty`` to mark the getter and
``@setproperty`` to mark the setter:
>>> from cybertools.util.property import getproperty, setproperty, delproperty
>>> class JamesBrown(object):
... @getproperty
... def feel(self):
... return self._feel
... @setproperty
... def feel(self, feel):
... self._feel = feel
>>> i = JamesBrown()
>>> i.feel
Traceback (most recent call last):
...
AttributeError: 'JamesBrown' object has no attribute '_feel'
>>> i.feel = "good"
>>> i.feel
'good'
The order in which getters and setters are declared doesn't matter:
>>> class JamesBrown(object):
... @setproperty
... def feel(self, feel):
... self._feel = feel
... @getproperty
... def feel(self):
... return self._feel
>>> i = JamesBrown()
>>> i.feel = "good"
>>> i.feel
'good'
Of course, deleters are also possible:
>>> class JamesBrown(object):
... @setproperty
... def feel(self, feel):
... self._feel = feel
... @getproperty
... def feel(self):
... return self._feel
... @delproperty
... def feel(self):
... del self._feel
>>> i = JamesBrown()
>>> i.feel = "good"
>>> del i.feel
>>> i.feel
Traceback (most recent call last):
...
AttributeError: 'JamesBrown' object has no attribute '_feel'
Edge cases
----------
There might be a case where you're using a flavour of read & write
properties and already have a non-property attribute of the same name
defined:
>>> class JamesBrown(object):
... feel = "good"
... @getproperty
... def feel(self):
... return "so good"
...
Traceback (most recent call last):
...
TypeError: read & write properties cannot be mixed with other attributes except regular property objects.