0

I have the following code:

class Test(object):

    _spam = 42

    @classmethod
    def get_spam(cls):
        cls._spam

    @classmethod
    def set_spam(cls, value):
        cls._spam = value

    spam = property(get_spam, set_spam)

print Test.spam
Test.spam = 24
print Test.spam

The output is:

<property object at 0x01E55BD0>
24

Is there any way to prevent the setting of Test.spam from overriding the property? I don't want to use Test.spam to set the value of Test._spam. The setter and getter have to remain as class methods, and I do not want to have to call Test.set_spam.

The output should be:

<property object at 0x01E55BD0>
<property object at 0x01E55BD0>
D K
  • 5,530
  • 7
  • 31
  • 45
  • 1
    The following question is similar to yours and contains a solution: http://stackoverflow.com/questions/128573/using-property-on-classmethods – flashk Aug 05 '11 at 21:03
  • So is there any way to prevent the setting of `Test.spam` from overriding the property (as I asked)? I'll edit my question to make it clearer. – D K Aug 05 '11 at 21:16
  • Shouldn't the output be `42` `24`? What is the purpose of having a "class property" if you can't actually see the value, but only the property object? – Karl Knechtel Aug 05 '11 at 22:00

1 Answers1

1

I suppose this stops developers from accidentally overwriting Test's spam property. Is that why you want this? I not sure that is a good idea (what if a developer wants to override the spam property? why throw up roadblocks?), but...

You could use a metaclass. If you don't supply a setter for the metaclass's property, then Test.spam will raise an AttributeError:

class MetaTest(type):
    @property
    def spam(cls):
        return cls._spam

class Test(object):
    __metaclass__=MetaTest
    _spam = 42

    @classmethod
    def get_spam(cls):
        cls._spam

    @classmethod
    def set_spam(cls, value):
        cls._spam = value

    spam = property(get_spam, set_spam)

print Test.spam
# 42

But

Test.spam = 24

raises

AttributeError: can't set attribute
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • This works great, but the excution of `get_spam` is overriden by the `spam` method of `MetaTest` (so `get_spam` is never executed and the point of having a property is taken away). – D K Aug 05 '11 at 21:43
  • @D K: A property in `Test` is meant to be used by instances of `Test`. That is, when you call `t=Test(); t.spam`, then `Test.get_spam(t)` gets called. Making the getter and setter classmethods upsets this setup -- I don't understand why you are making them classmethods... It doesn't seem right to me. By the way, in the code you posted, `get_spam` never gets executed either. `Test.spam` only returns the property object. – unutbu Aug 05 '11 at 22:00
  • Oh, I see. My question is a bit warped, isn't it? I'll mark your answer as correct, rethink just exactly what I'm after, and then I'll post a new question that makes more sense. Basically what I want is a property that cannot be set and cannot be overriden (like a read-only property). – D K Aug 05 '11 at 22:16