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