8

The following doesn't work for some reason:

>>> class foo(object):
...     @property
...     @classmethod
...     def bar(cls):
...             return "asdf"
... 
>>> foo.bar
<property object at 0x1da8d0>
>>> foo.bar + '\n'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'property' and 'str'

Is there a way to do this, or is my only alternative to resort to some kind of metaclass trickery?

1

1 Answer 1

7

If you want the descriptor property to trigger when you get an attribute from object X, then you must put the descriptor in type(X). So if X is a class, the descriptor must go in the class's type, also known as the class's metaclass -- no "trickery" involved, it's just a matter of completely general rules.

Alternatively, you might write your own special-purpose descriptor. See here for an excellent "how-to" treaty on descriptors. Edit for example:

class classprop(object):
  def __init__(self, f):
    self.f = classmethod(f)
  def __get__(self, *a):
    return self.f.__get__(*a)()

class buh(object):
  @classprop
  def bah(cls): return 23

print buh.bah

emits 23, as desired.

Sign up to request clarification or add additional context in comments.

2 Comments

I'm using a metaclass elsewhere in the inheritance hierarchy, so if I use the metaclass, I get the following: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
@Jason, you could also use a subclass of all involved metaclasses, as the error message says (few use multiple custom metaclasses, or metaclasses that don't subclass type, so probably you only need to subclass the one custom metaclass you're using) -- but if the custom descriptor does the job, it may indeed be a simpler approach.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.