John Posner a écrit :
On 3/3/2010 6:56 PM, John Posner wrote:

... I was thinking
today about "doing a Bruno", and producing similar pieces on:

* properties created with the @property decorator

* the descriptor protocol

I'll try to produce something over the next couple of days.


Starting to think about a writeup on Python properties, I've discovered that the official Glossary [1] lacks an entry for "property" -- it's missing in both Py2 and Py3!

Here's a somewhat long-winded definition -- comments, please:

---------------------------------------------
An attribute, *a*, of an object, *obj*, is said to be implemented as a property if the standard ways of accessing the attribute:

 * evaluation:      print obj.a
 * assignment:      obj.a = 42
 * deletion:        del obj.a

... cause methods of a user-defined *property object* to be invoked.

Hmmm... a couple remarks:

1/ "property" is actually the name of a Python builtin type. It's also pretty much used in general OO litterature for what we name "attributes". So I think it would be better to avoid confusion between "property" as the builtin type, "property" as synonym for attribute, and "property" as the more specific concept of "computed attribute" - which is what you're describing here.

As far as I'm concerned, I prefer to stick to "computed attribute" for the generic case, and only use "property" when the computed attribute is actually implemented using the builtin property type.

2/ depending on how the computed attribute is implemented, the computation needs not happen on ALL get/set/del access - you can have non-binding descriptors (that is, not implementing __set__).

Also, the "standard" access also include getattr(), setattr() and delattr() (might be worth a note).

The attribute

/attribute/user-defined object/ here ?

is created as a class attribute, not an instance attribute. Example:

  class Widget:
      # create "color" as class attribute, not within __init__()
      color = <<property-object>>

      def __init__(self, ...):
          # do not define "self.color" instance attribute

Yes you can, and it's even actually pretty common:

# example.py
from somewhere import RGBColor

class Foo(object):
   def _get_color(self):
       return str(self._color)
   def _set_color(self, val):
       self._color = RGBColor.from_string(val)
   color = property(fget=_get_color, fset=_set_color)

   def __init__(self, colorvalue):
       self.color = colorvalue


The property object can be created with the built-in function property(),

It's actually a type, not a function.

which in some cases can be coded as a decorator: @property. The property object can also be an instance of a class that implements the descriptor protocol.

The "property object" IS an instance of a class that implements the descriptor protocol. The property type is just a "generic" descriptor:

# naive (and incomplete) python implementation of the property type

class property(object):
    def __init__(self, fget, fset=None, fdel=None)
        self._fget = fget
        self._fset = fset
        self._fdel = fdel

   def __get__(self, instance, cls):
       if instance is None:
           return self
       return self._fget(instance)

   def __set__(self, instance, value):
       if not self._fset:
           raise AttributeError("can't set attribute")
       self._fset(instance, value)

   def __del__(self):
       if not self._fdel:
           raise AttributeError("can't delete attribute")
       self._fdel(instance)


As far as I'm concerned, I'd "plan" such a paper as:

"""
What's a property ? It's a computed attribute implemented using the builtin "property" type.

Ok, so far it doesn't help much. So
1/ what's a computed attribute, and
2/ what is the property type ?

1/ your above explanation about what's a computed attribute in general, then a brief explanation of how computed attributes are implemented in python -> IOW, the descriptor protocol

2/ my above snippet !-)

"""

I think the way you started explaining computed attributes wrt/ attribute access could be a pretty good way to explain the descriptor protocol, since the mapping from get/set/del access to __get__, __set__, and __del__ magic methods is then pretty obvious.

But YMMV of course, so by all mean feel free to discard all or parts of the above remarks !-)

HTH
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to