Immutability

N

Nick Maclaren

|>
|> identical? you only applied @property to one of the methods, and then you're
|> surprised that only one of the methods were turned into a property?

I wasn't expecting EITHER to be turned INTO a property - I was expecting
both methods to be the same, but one would have non-default properties
attached to it.

|> @property turns your "joe" method into a getter method for the (virtual) attribute
|> "joe". when you access the attribute, the getter method will be called. whatever
|> that method returns will be the attribute's value.

Ah! That clarifies a lot.

|> that's what the documentation
|> says, and that's what your code is doing.

Er, no, it doesn't. What it says may well be COMPATIBLE with that, but
it is compatible with a good many other interpretations, too. Until and
unless you know what it means, you can't extract its meaning from its
words.


Regards,
Nick Maclaren.
 
R

Roel Schroeven

Nick Maclaren schreef:
Most especially since it isn't working very well for me, and I am trying
to track down why. When I run:
class fred :
@property
def joe (self) :
print "Inside /joe\n"

a = fred()
a.joe()

I get:

Inside joe

Traceback (most recent call last):
File "crap.py", line 14, in <module>
a.joe()
TypeError: 'NoneType' object is not callable

Since joe is a property, you shouldn't access it as a method. This works:

a = fred()
a.joe

Inside joe


If you call it as a function, first the function is executed (printing
"Inside joe"), but then Python tries to call the return value of the
function, which is None.
 
B

Bruno Desthuilliers

Fredrik said:
Bruno Desthuilliers wrote:




property getters work just fine on old-style classes (setters and deleters don't
work, but that's not what he's using).

Thanks - I was too lazy to actually reread all the doc or derive this
from observation !-)
 
F

Fredrik Lundh

Nick said:
I wasn't expecting EITHER to be turned INTO a property - I was expecting
both methods to be the same, but one would have non-default properties
attached to it.
|> that's what the documentation
|> says, and that's what your code is doing.

Er, no, it doesn't. What it says may well be COMPATIBLE with that, but
it is compatible with a good many other interpretations, too. Until and
unless you know what it means, you can't extract its meaning from its
words.

well, I completely fail to see how the following is compatible with the
interpretation "attaches a non-default property, but doesn't do anything
else":

property([fget[, fset[, fdel[, doc]]]]) => descriptor

Returns a property attribute for new-style classes (classes that
derive from object).

fget is a function for getting an attribute value, likewise fset is a
function for setting, and fdel a function for deleting, an
attribute. Typical use is to define a managed attribute x:

class C(object):
def __init__(self): self.__x = None
def getx(self): return self.__x
def setx(self, value): self.__x = value
def delx(self): del self.__x
x = property(getx, setx, delx, "I'm the 'x' property.")

</F>
 
N

Nick Maclaren

|>
|> well, I completely fail to see how the following is compatible with the
|> interpretation "attaches a non-default property, but doesn't do anything
|> else":

Because I was using a decorator and defining an attribute directly.
But no matter - it is clear I had completely misunderstood the intent.


Regards,
Nick Maclaren.
 
D

Duncan Booth

Georg said:
In my opinion property isn't really meant to be used as a decorator since
it's impossible to create a read-write property. The decorator pattern
doesn't really fit here.
I agree that property isn't currently intended to be used as a decorator,
but it isn't actually *impossible* to create a read-write property using
decorators. Here is one way:

--------- props.py ----------------
from inspect import getouterframes, currentframe
import unittest

class property(property):
@classmethod
def get(cls, f):
locals = getouterframes(currentframe())[1][0].f_locals
prop = locals.get(f.__name__, property())
return cls(f, prop.fset, prop.fdel, prop.__doc__)

@classmethod
def set(cls, f):
locals = getouterframes(currentframe())[1][0].f_locals
prop = locals.get(f.__name__, property())
return cls(prop.fget, f, prop.fdel, prop.__doc__)

@classmethod
def delete(cls, f):
locals = getouterframes(currentframe())[1][0].f_locals
prop = locals.get(f.__name__, property())
return cls(prop.fget, prop.fset, f, prop.__doc__)

class PropTests(unittest.TestCase):
def test_setgetdel(self):
class C(object):
def __init__(self, colour):
self._colour = colour

@property.set
def colour(self, value):
self._colour = value

@property.get
def colour(self):
return self._colour

@property.delete
def colour(self):
self._colour = 'none'

inst = C('red')
self.assertEquals(inst.colour, 'red')
inst.colour = 'green'
self.assertEquals(inst._colour, 'green')
del inst.colour
self.assertEquals(inst._colour, 'none')

if __name__=='__main__':
unittest.main()
-----------------------------------
 
G

Georg Brandl

Duncan said:
I agree that property isn't currently intended to be used as a decorator,
but it isn't actually *impossible* to create a read-write property using
decorators. Here is one way:

Yes, I only wanted to say that it isn't possible by just using the builtin
property function as a decorator.

Georg
 
G

Georg Brandl

Nick said:
|>
|> identical? you only applied @property to one of the methods, and then you're
|> surprised that only one of the methods were turned into a property?

I wasn't expecting EITHER to be turned INTO a property - I was expecting
both methods to be the same, but one would have non-default properties
attached to it.

That's another sign that property isn't intended to be used as a decorator.
Normally, decorators wrap functions with other functions. property doesn't
return a function but a descriptor object.

Georg
 
B

Bruno Desthuilliers

Georg Brandl a écrit :
That's another sign that property isn't intended to be used as a decorator.
Normally, decorators wrap functions with other functions.

Normally, decorators take a function and return anything appropriate.
property doesn't
return a function but a descriptor object.

FWIW, function *are* descriptors (well, Python functions at least, cf
the recent thread about pyrex functions).
 
B

Bruno Desthuilliers

Georg Brandl a écrit :
Steve Holden wrote:




In my opinion property isn't really meant to be used as a decorator since
it's impossible to create a read-write property. The decorator pattern
doesn't really fit here.

Making an attribute read-only is a common use case for properties, so
using property as a decorator in this case seems quite ok.
 
B

Bruno Desthuilliers

Bruno Desthuilliers a écrit :
Georg Brandl a écrit : (snip)


Normally, decorators take a function and return anything appropriate.
>

So do classmethod.
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
 
S

Steve Holden

Georg said:
That's another sign that property isn't intended to be used as a decorator.
Normally, decorators wrap functions with other functions. property doesn't
return a function but a descriptor object.
OK, I still think the docs need updating, but to explain the above as
the reason *why* property's use as a decorator is not advised. Or is it
stylistically and semantically acceptable in the case of a read-only
property?

Would it make sense, in the single argument case, to default the doc
value to fget.__doc__ to support that use case, or should we just not
create read-only properties by using property as a decorator?

regards
Steve
 
G

Georg Brandl

Steve said:
OK, I still think the docs need updating, but to explain the above as
the reason *why* property's use as a decorator is not advised. Or is it
stylistically and semantically acceptable in the case of a read-only
property?

I'm not the one to judge over that.
Would it make sense, in the single argument case, to default the doc
value to fget.__doc__ to support that use case, or should we just not
create read-only properties by using property as a decorator?

This is actually already the case in 2.5.

Georg
 
S

Steve Holden

Georg said:
Steve Holden wrote: [...]
Would it make sense, in the single argument case, to default the doc
value to fget.__doc__ to support that use case, or should we just not
create read-only properties by using property as a decorator?


This is actually already the case in 2.5.
Sorry, haven't had much time for python-checkins lately. But this would
certainly argue that the decorator form for read-only properties is
accepted at some level.

regards
Steve
 
K

Kay Schluehr

Nick said:
|> > The way that I read it, Python allows only values (and hence types)
|> > to be immutable, and not class members. The nearest approach to the
|> > latter is to use the name hiding conventions.
|> >
|> > Is that correct?
|>
|> You can also make properties that don't allow writing.
|>
|> class Foo(object):
|>
|> def __init__(self, bar):
|> self._bar = bar
|>
|> @property
|> def bar(self):
|> return self._bar

Thanks very much. And, what's more, I have even found its documentation!
Whatsnew2.2. The 2.4.2 reference is, er, unhelpful.

One of Python's less-lovable attributes is the inscrutability of its
documentation :-(

But you knew that ....


Regards,
Nick Maclaren.

When I want to read about descriptors I use Raymond Hettingers "How To"
article which explains the matter quite fine:

http://users.rcn.com/python/download/Descriptor.htm
 
G

Georg Brandl

Steve said:
Georg said:
Steve Holden wrote: [...]
Would it make sense, in the single argument case, to default the doc
value to fget.__doc__ to support that use case, or should we just not
create read-only properties by using property as a decorator?


This is actually already the case in 2.5.
Sorry, haven't had much time for python-checkins lately.

I didn't want to offend you, I must know since I implemented it myself ;)
But this would
certainly argue that the decorator form for read-only properties is
accepted at some level.

Yes, one could argue in this direction. I will ask on python-dev whether
an official hint should be added to the documentation.

Georg
 
G

Georg Brandl

Georg said:
Steve said:
Georg said:
Steve Holden wrote: [...]

Would it make sense, in the single argument case, to default the doc
value to fget.__doc__ to support that use case, or should we just not
create read-only properties by using property as a decorator?


This is actually already the case in 2.5.
Sorry, haven't had much time for python-checkins lately.

I didn't want to offend you, I must know since I implemented it myself ;)
But this would
certainly argue that the decorator form for read-only properties is
accepted at some level.

Yes, one could argue in this direction. I will ask on python-dev whether
an official hint should be added to the documentation.

Okay, this is now documented in the trunk.

Georg
 
V

vatamane

That is why I don't like the use of @property. Even though the
decorator is a nice short-hand notation, it is more confusing in my
oppinion. So someone is more likely still call the property as a
function when looking at:

class C:
@property
def data(self):
return 42

rather than if they saw:

class C:
def _data(self):
return 42
data=property(_data)

I personally I find the second case more readable, even though it is
longer.

-Nick
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,470
Messages
2,571,807
Members
48,797
Latest member
PeterSimpson
Top