Essentially I want to do something like this:
class foo: x = 4 @property @classmethod def number(cls): return x
Then I would like the following to work:
>>> foo.number 4
Unfortunately, the above doesn't work. Instead of given me 4
it gives me <property object at 0x101786c58>
. Is there any way to achieve the above?
If you need to make a read-only attribute in Python, you can turn your attribute into a property that delegates to an attribute with almost the same name, but with an underscore prefixed before the its name to note that it's private convention.
To define a readonly property, you need to create a property with only the getter. However, it is not truly read-only because you can always access the underlying attribute and change it. The read-only properties are useful in some cases such as for computed properties.
Python property() function returns the object of the property class and it is used to create property of a class. Parameters: fget() – used to get the value of attribute. fset() – used to set the value of attribute.
The @property Decorator In Python, property() is a built-in function that creates and returns a property object. The syntax of this function is: property(fget=None, fset=None, fdel=None, doc=None)
This will make Foo.number
a read-only property:
class MetaFoo(type): @property def number(cls): return cls.x class Foo(object, metaclass=MetaFoo): x = 4 print(Foo.number) # 4 Foo.number = 6 # AttributeError: can't set attribute
Explanation: The usual scenario when using @property
looks like this:
class Foo(object): @property def number(self): ... foo = Foo()
A property defined in Foo
is read-only with respect to its instances. That is, foo.number = 6
would raise an AttributeError
.
Analogously, if you want Foo.number
to raise an AttributeError
you would need to setup a property defined in type(Foo)
. Hence the need for a metaclass.
Note that this read-onlyness is not immune from hackers. The property can be made writable by changing Foo's class:
class Base(type): pass Foo.__class__ = Base # makes Foo.number a normal class attribute Foo.number = 6 print(Foo.number)
prints
6
or, if you wish to make Foo.number
a settable property,
class WritableMetaFoo(type): @property def number(cls): return cls.x @number.setter def number(cls, value): cls.x = value Foo.__class__ = WritableMetaFoo # Now the assignment modifies `Foo.x` Foo.number = 6 print(Foo.number)
also prints
6
The property
descriptor always returns itself when accessed from a class (ie. when instance
is None
in its __get__
method).
If that's not what you want, you can write a new descriptor that always uses the class object (owner
) instead of the instance:
>>> class classproperty(object): ... def __init__(self, getter): ... self.getter= getter ... def __get__(self, instance, owner): ... return self.getter(owner) ... >>> class Foo(object): ... x= 4 ... @classproperty ... def number(cls): ... return cls.x ... >>> Foo().number 4 >>> Foo.number 4
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With