[Tutor] classproperty for Python 2.7 (read-only enough)
eryk sun
eryksun at gmail.com
Wed Apr 19 10:55:27 EDT 2017
On Wed, Apr 19, 2017 at 10:19 AM, Peter Otten <__peter__ at web.de> wrote:
> Steven D'Aprano wrote:
>
>> As I said, I haven't had a chance to try Peter's code, so it's possible
>> that he's solved all these problems. I'm judging by previous
>
> No, my simple code only "works" for read-only properties and only as long as
> you don't overwrite the property by assigning to the attribute. To disallow
> writing you can define a
>
> def __set__(*args):
> raise AttributeError
>
> method, but that would only be invoked for instances of the class, not the
> class itself. For the same reason the setter of a read/write class property
> following that design would only be invoked in an instance, not in the
> class.
>
> The other simple solution, defining a normal property in the metaclass,
> works for the class (as expected, remember that the class is an instance of
> the metaclass), but is invisible to the instance:
>
>>>> class T(type):
> ... @property
> ... def foo(self): return 42
> ...
>>>> class Foo:
> ... __metaclass__ = T
> ...
>>>> Foo.foo
> 42
>>>> Foo.foo = "bar"
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> AttributeError: can't set attribute
>>>> Foo().foo
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> AttributeError: 'Foo' object has no attribute 'foo'
This is a bit awkward, but you can take advantage of property() being
a data descriptor. When the attribute is looked up on the class, the
metaclass __getattribute__ or __setattr__ first searches the metaclass
MRO. If it finds a data descriptor, then it uses it unconditionally.
This means you can add a foo property to the class as well and have it
chain to the metaclass property. For example:
class T(type):
@property
def foo(self):
return 42
class C(object):
__metaclass__ = T
@property
def foo(self):
return type(self).foo
>>> C.foo
42
>>> C.foo = 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>> o = C()
>>> o.foo
42
>>> o.foo = 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
More information about the Tutor
mailing list