Method / Functions - What are the differences?

John Posner jjposner at optimum.net
Fri Mar 5 16:10:51 CET 2010


On 3/5/2010 7:15 AM, Bruno Desthuilliers wrote:
> 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.

Yes, I had already decided that the first sentence of the glossary 
definition needs to be, "A property is a computed attribute".

>
> 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__).

Yes, but IMHO that information belongs in the full writeup, not in the 
glossary definition. I've added the phrase "some or all" in the glossary 
definition (see below).

> 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:

Of course -- and I realize that I was introducing confusion, rather than 
enlightenment, with my example. I think the point is too subtle for a 
(necessarily short) glossary definition, so I'm removing the example 
from the definition.

>
> # 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

[OFF-TOPIC] Wow, Thunderbird 3.0.2 nuked the indentation in the code 
above. :-(

>
>
>> The property object can be created with the built-in function property(),
>
> It's actually a type, not a function.

Ah, yes. Thanks.

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

Good stuff for the full writeup on properties.


> 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 agree. I'm not sure whether the "brief explanation of how computed 
attributes are implemented in Python" belongs in the *properties* 
writeup or the *descriptors* writeup. (I think they should be separate, 
to avoid making readers brains explode.) I'll make the (initial) call 
when/if I get that far!


>
> """
>
> 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


Here's my leaner, meaner glossary definition of *property*:

-------------------
A property is a computed attribute: an attribute, a, of an object, obj, 
is said to be implemented as a property if some or all of the standard 
ways of accessing the attribute:

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

... cause methods of another user-defined object to be invoked. This 
other object can be an instance of the built-in type *property*, or as 
an instance of a class that implements the descriptor protocol.
-------------------

Many thanks, Bruno -- again!

-John



More information about the Python-list mailing list