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:
		
							parent
							
								
									b4dd7ccddd
								
							
						
					
					
						commit
						53ae9f332a
					
				
					 2 changed files with 177 additions and 3 deletions
				
			
		|  | @ -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$ | ||||
| """ | ||||
|  | @ -39,3 +41,76 @@ class lzprop(object): | |||
|         value = self.func(inst) | ||||
|         inst.__dict__[self.func.__name__] = 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) | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ $Id$ | |||
| 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 | ||||
| extremely useful when working with objects of a limited lifetime (e.g. | ||||
| adapters) that provide results from expensive calculations. | ||||
|  | @ -52,3 +52,102 @@ already during compilation or object creation): | |||
|     >>> demo2.value | ||||
|     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. | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 helmutm
						helmutm