Method / Functions - What are the differences?
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  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
>> 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")
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 !-)
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!
More information about the Python-list