1

To define a property, we can use

class MyClass(object):

    def __init__(f):
        self._f = f

    def custom_function(self):
        self._f += 1

    @property
    def f(self):
        return self._f

such that

>>x = MyClass(1)
>>print(x.f)  # prints 2

Is there any standard way to define the interface

>>MyClass.f  # <- calls custom classmethod

? I.e. a "@classproperty".

I'm aware of @classmethod but I don't want the interface to have the call ().

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Jorge Leitao
  • 19,085
  • 19
  • 85
  • 121
  • 1
    Closely related: [Implementing a class property that preserves the docstring](http://stackoverflow.com/q/22357961), and also [Python, how does the @property decorator work?](http://stackoverflow.com/q/17330160) (for the details on how a property resolves). – Martijn Pieters Jun 19 '14 at 12:10
  • 1
    Your options are to use a regular `@property` on a method on the *metaclass*, or to create a custom descriptor that handles access on the class. – Martijn Pieters Jun 19 '14 at 12:12
  • @MartijnPieters, `@property` on the meta! That's it! – Jorge Leitao Jun 19 '14 at 12:16

1 Answers1

1

You have two options: Put a property on the metaclass, or create a custom descriptor to translate a .__get__ directly into a function call, regardless of the context; the property descriptor only does this when there is an instance, returning self for when accessed on the class.

Metaclass:

class MetaClass(type):
    @property
    def f(cls):
        return cls._f

class MyClass(object):
    __metaclass__ = MetaClass

    def __init__(f):
        self._f = f

Custom descriptor:

class classproperty(object):
    def __init__(self, getter):
        self.getter = getter

    def __get__(self, instance, cls):
        return self.getter(cls)

class MyClass(object):
    def __init__(f):
        self._f = f

    @classproperty
    def f(cls):
        return cls._f

Be aware that there are limitations to the latter approach.

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343