Re: [Python-Dev] Declaring setters with getters
At 11:09 AM 10/31/2007 -0700, Guido van Rossum wrote:
Yes, though I think that if prop.fdel is None, we could use func in both slots.
Eh? Isn't prop.fdel supposed to be a single-argument function? ISTM that C is the only place where fset and fdel are the same thing.
On 10/31/07, Phillip J. Eby
At 11:09 AM 10/31/2007 -0700, Guido van Rossum wrote:
Yes, though I think that if prop.fdel is None, we could use func in both slots.
Eh? Isn't prop.fdel supposed to be a single-argument function? ISTM that C is the only place where fset and fdel are the same thing.
Given how rarely supporting deletions matters enough to write extra code, we can just say that *when using @propset* your setter function needs to have a default value for the argument or otherwise support being called with one or two arguments. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Oct 31, 2007, at 4:28 PM, Guido van Rossum wrote:
Given how rarely supporting deletions matters enough to write extra code, we can just say that *when using @propset* your setter function needs to have a default value for the argument or otherwise support being called with one or two arguments.
It's definitely unusual, but the logic is typically very different; conflating the method in Python doesn't really feel "right" to me. I've been using Philipp von Weitershausen's "rwproperty" quite happily: http://pypi.python.org/pypi/rwproperty/ It uses the names "getproperty", "setproperty", and "delproperty", which feel reasonable when I use them (always referenced using the module), like so: class Thing(object): @rwproperty.setproperty def attribute(self, value): # ... If I had to choose built-in names, though, I'd prefer "property", "propset", "propdel". Another possibility that seems reasonable (perhaps a bit better) would be: class Thing(object): @property def attribute(self): return 42 @property.set def attribute(self, value): self._ignored = value @property.delete def attribute(self): pass -Fred -- Fred Drake <fdrake at acm.org>
On 10/31/07, Fred Drake
If I had to choose built-in names, though, I'd prefer "property", "propset", "propdel". Another possibility that seems reasonable (perhaps a bit better) would be:
class Thing(object):
@property def attribute(self): return 42
@property.set def attribute(self, value): self._ignored = value
@property.delete def attribute(self): pass
+1 on this spelling if possible. Though based on Guido's original recipe it might have to be written as:: @property.set(attribute) def attribute(self, value): self._ignored = value STeVe -- I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a tiny blip on the distant coast of sanity. --- Bucky Katt, Get Fuzzy
As long as we're all tossing out ideas here, my 2�. I vastly prefer this: On 02:43 am, steven.bethard@gmail.com wrote:
On 10/31/07, Fred Drake
wrote:
@property.set def attribute(self, value): self._ignored = value
to this:
@property.set(attribute) def attribute(self, value): self._ignored = value
since I don't see any additional expressive value in the latter, and it provides an opportunity to make a mistake. The decorator syntax's main value, to me, is eliminating the redundancy in: def foo(): ... foo = bar(foo) eliminating the possibility of misspelling "foo" one of those three times. and removing a lot of finger typing. The original proposal here re-introduces half of this redundancy. I think I can see why Guido did it that way - it makes the implementation a bit more obvious - but decorators are already sufficiently "magic" that I wouldn't mind a bit more to provide more convenience, in what is apparently just a convenience mechanism. And, since everyone else is sharing their personal current way of idiomatically declaring dynamic properties, here's mine; abusing the "class" statement instead of decorators: from epsilon.descriptor import attribute class Stuff(object): class foo(attribute): "you can put a docstring in the obvious place" def set(self, value): print 'set foo!' self._foo = value + 4 def get(self): return self._foo + 3 s = Stuff() s.foo = 0 print 's.foo:', s.foo I'd be glad of a standard, accepted way to do this though, since it's really just a spelling issue and it would be nice to reduce the learning curve between all the different libraries which define dynamic attributes.
On 10/31/07, glyph@divmod.com
As long as we're all tossing out ideas here, my 2¢. I vastly prefer this:
On 02:43 am, steven.bethard@gmail.com wrote:
On 10/31/07, Fred Drake
wrote: @property.set def attribute(self, value): self._ignored = value
to this:
@property.set(attribute) def attribute(self, value): self._ignored = value
since I don't see any additional expressive value in the latter, and it provides an opportunity to make a mistake.
I was expecting this would be brought up, but that just ain't gonna happen. If you don't repeat the name, the decorator has to root around in the surrounding scope, which is fraught with peril. Solutions based on sys._getframe() have been around for years (e.g. several the Cookbook recipes) and if I had approved of that technique I would have adopted one long ago. However I don't approve of it. It has always been and will always continue to be my position that these are semantically unkosher, because it means that you can't wrap them in convenience functions or invoke them in different contexts, and that means that the semantics are hard to explain. If you really want another argument, repeating the property name actually does have an additional use case: you can have a read-only property with a corresponding read-write property whose name differs. E.g. class C(object): @property def encoding(self): return ... @propset(encoding) def encoding_rw(self, value): ... c = C() c.encoding = "ascii" # Fails c.encoding_rw = "ascii" # Works I've seen people do this in the filesystem: a read-only version that may be cached or replicated, and a separate writable version. Reading the writable version works too, of course. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Nov 1, 2007, at 10:01 AM, Guido van Rossum wrote:
On 10/31/07, glyph@divmod.com
wrote: As long as we're all tossing out ideas here, my 2¢. I vastly prefer this:
On 02:43 am, steven.bethard@gmail.com wrote:
On 10/31/07, Fred Drake
wrote: @property.set def attribute(self, value): self._ignored = value
to this:
@property.set(attribute) def attribute(self, value): self._ignored = value
since I don't see any additional expressive value in the latter, and it provides an opportunity to make a mistake.
I was expecting this would be brought up, but that just ain't gonna happen. If you don't repeat the name, the decorator has to root around in the surrounding scope, which is fraught with peril. Solutions based on sys._getframe() have been around for years (e.g. several the Cookbook recipes) and if I had approved of that technique I would have adopted one long ago.
It's also not as if you're writing some string value the second time, so any typos in the name will be caught early on. - -Barry -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (Darwin) iQCVAwUBRyoLjnEjvBPtnXfVAQKcHAQAt8cmfJa93nVMX4/cIUTzUvke2LMhiKbj 5auo/TlymK6GMrKCLSpIOVfxMboj0tf5RqL8oS72OS6w6K+jlBiVFRZPf0NQtO1s WXsKDR/tw5B8iiTsoi8CRASsbEBetTrHIa5WqWqYbNk1sE7GNGTK4kIGoMd1txyp IdhLvYSJK7Q= =v4I7 -----END PGP SIGNATURE-----
On 02:01 pm, guido@python.org wrote:
On 10/31/07, glyph@divmod.com
wrote: As long as we're all tossing out ideas here, my 2�. I vastly prefer this:
@property.set
to this: @property.set(attribute)
I don't approve of it. It has always been and will always continue to be my position that these are semantically unkosher, because it means that you can't wrap them in convenience functions or invoke them in different contexts, and that means that the semantics are hard to explain.
Point taken.
If you really want another argument, repeating the property name actually does have an additional use case: you can have a read-only property with a corresponding read-write property whose name differs.
I don't actually have this use-case, but it does make the actual semantics of the provided argument a bit clearer to me. It's not an implementation detail of fusing the properties together, it's just saying which property to get the read accessor from. This is a minor nit, as with all decorators that take an argument, it seems like it sets up a hard-to-debug error condition if you were to accidentally forget it: @property def foo(): ... @property.set def foo(): ... would leave you with 'foo' pointing at something that wasn't a descriptor at all. Is there a way to make that more debuggable?
On 11/1/07, glyph@divmod.com
This is a minor nit, as with all decorators that take an argument, it seems like it sets up a hard-to-debug error condition if you were to accidentally forget it:
@property def foo(): ... @property.set def foo(): ...
would leave you with 'foo' pointing at something that wasn't a descriptor at all. Is there a way to make that more debuggable?
Yes, if you remember my initial post, it contained this line: assert isinstance(prop, property) And even without that, accessing prop.fget would fail immediately; so instead of a non-functioning property, you get an exception at class definition time. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Nov 1, 2007, at 10:26 AM, glyph@divmod.com wrote:
This is a minor nit, as with all decorators that take an argument, it seems like it sets up a hard-to-debug error condition if you were to accidentally forget it:
@property def foo(): ... @property.set def foo(): ...
would leave you with 'foo' pointing at something that wasn't a descriptor at all. Is there a way to make that more debuggable?
How about this: give the property instance a method that changes a property from read-only to read-write. No parens, no frame magic. As a small bonus, the setter function would not have to be named the same as the property. class A(object): @property def foo(self): return 1 @foo.setter def set_foo(self, value): print 'set:', value -Tony
-1. Looks like more magic, not less, to me.
On 11/1/07, Tony Lownds
On Nov 1, 2007, at 10:26 AM, glyph@divmod.com wrote:
This is a minor nit, as with all decorators that take an argument, it seems like it sets up a hard-to-debug error condition if you were to accidentally forget it:
@property def foo(): ... @property.set def foo(): ...
would leave you with 'foo' pointing at something that wasn't a descriptor at all. Is there a way to make that more debuggable?
How about this: give the property instance a method that changes a property from read-only to read-write. No parens, no frame magic. As a small bonus, the setter function would not have to be named the same as the property.
class A(object): @property def foo(self): return 1
@foo.setter def set_foo(self, value): print 'set:', value
-Tony
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
"Steven Bethard"
On 10/31/07, Fred Drake
wrote: If I had to choose built-in names, though, I'd prefer "property", "propset", "propdel". Another possibility that seems reasonable (perhaps a bit better) would be:
class Thing(object):
@property def attribute(self): return 42
@property.set def attribute(self, value): self._ignored = value
@property.delete def attribute(self): pass
+1 on this spelling if possible. Though based on Guido's original recipe it might have to be written as::
@property.set(attribute) def attribute(self, value): self._ignored = value
It *can* be written as Fred suggested: see http://groups.google.co.uk/group/comp.lang.python/browse_thread/thread/b442d... However that depends on hacking the stack frames, so the implementation probably isn't appropriate here.
Fred Drake wrote:
@property def attribute(self): return 42
@property.set def attribute(self, value): self._ignored = value
Hmmm... if you were allowed general lvalues as the target of a def, you could write that as def attribute.set(self, value): ... -- Greg
Greg Ewing
Fred Drake wrote:
@property def attribute(self): return 42
@property.set def attribute(self, value): self._ignored = value
Hmmm... if you were allowed general lvalues as the target of a def, you could write that as
def attribute.set(self, value): ...
Dotted names would be sufficient rather than general lvalues. I like this, I think it looks cleaner than the other options, especially if you write both getter and setter in the same style: attribute = property() def attribute.fget(self): return 42 def attribute.fset(self, value): self._ignored = value
On 11/2/07, Duncan Booth
Greg Ewing
wrote: Fred Drake wrote:
@property def attribute(self): return 42
@property.set def attribute(self, value): self._ignored = value
Hmmm... if you were allowed general lvalues as the target of a def, you could write that as
def attribute.set(self, value): ...
Dotted names would be sufficient rather than general lvalues.
I like this, I think it looks cleaner than the other options, especially if you write both getter and setter in the same style:
attribute = property()
def attribute.fget(self): return 42
def attribute.fset(self, value): self._ignored = value
Sorry, you have just entered Python 4000 territory. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
participants (9)
-
Barry Warsaw
-
Duncan Booth
-
Fred Drake
-
glyph@divmod.com
-
Greg Ewing
-
Guido van Rossum
-
Phillip J. Eby
-
Steven Bethard
-
Tony Lownds