21

I have a class like this:

class Foo(object):
    def __init__(self):
        self.bar = property(self.get_bar)

    def get_bar(self):
        return "bar"

print Foo().bar  #this prints <property object at 0x0051CB40>

I've seen How do Python properties work?, How to set a python property in __init__, but they all use the decorator method, which i don't because i want a different name. And I need access to self

How do i get the property to behave?

Community
  • 1
  • 1
gcq
  • 817
  • 3
  • 12
  • 19
  • 2
    Why would you like to use different name? Is there a reasonable reason? – Stan Prokop Feb 16 '14 at 14:01
  • Have you tried using property as a decorator or with a docstring? – Michael Aaron Safyan Feb 16 '14 at 14:02
  • A quick solution will be to call `__get__` on `bar` explicitly: `f = Foo();f.bar.__get__(f, type(f))` – Ashwini Chaudhary Feb 16 '14 at 14:16
  • 11
    (since this is the first web hit I found for my problem:) One other reason a property object can be returned instead of the property (even if the correct way of writing the property is used) is if the class is not instantiated into an object: print(Foo.bar) instead of print(Foo().bar) – Michael Scott Asato Cuthbert Sep 09 '15 at 20:36
  • 2
    @MichaelScottCuthbert I think you should add this as an alternative answer, despite not being directly related with the question. I had this problem and your comment saved me! Thank you! – jmpcm Mar 02 '18 at 15:21

5 Answers5

19

You need to make a minor change:

class Foo(object):

    def get_bar(self):
        return "bar"

    bar = property(get_bar)

print Foo().bar # prints bar

The property needs to be an attribute of the class, not the instance; that's how the descriptor protocol works.

jonrsharpe
  • 107,083
  • 22
  • 201
  • 376
8

You can do it like this

class Foo(object):
    def __init__(self):
        self.__bar = None

    def get_bar(self):
        return self.__bar

    def set_bar(self, value):
        self.__bar = value

    bar = property(get_bar, set_bar)

foo = Foo()
print foo.bar    # None
foo.bar = 1
print foo.bar    # 1
thefourtheye
  • 221,210
  • 51
  • 432
  • 478
6

You can also do it like shown here:

class Foo(object):
    def __init__(self):
        self._bar = None

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, value):
        self._bar = value

    @bar.deleter
    def bar(self):
        self._bar = None # for instance

which is equivalent to:

class Also_Foo(object):
    def __init__(self):
        self._bar = None

    def get_bar(self):
        return self._bar

    def set_bar(self, value):
        self._bar = value

    def del_bar(self):
        self._bar = None # for instance

    bar = property(fget=get_bar, fset=set_bar, fdel=del_bar, doc=None)

BUT without polluting the class namespace with get and set methods for each attribute.

You retain external direct access to the variable by using ._bar instead of .bar.

berna1111
  • 1,739
  • 1
  • 19
  • 19
4

The object is not instantiated.

class Foo(object):
  def get_bar(self):
    return "bar"

bar = Foo()
print(bar.get_bar)
David Parks
  • 28,443
  • 44
  • 166
  • 295
warchitect
  • 347
  • 1
  • 2
  • 15
  • This was the correct answer for me. I had done `Foo.get_bar` rather than `Foo().get_bar`. E.g., the object was not instantiated. – David Parks Jun 19 '19 at 17:10
  • Lol, it was my case too. After ~30 minutes of debbugging I found some place deep in the code where the property was read from class, not instance... – Andrey Semakin Nov 05 '19 at 12:24
0

My use case required defining bar as a property only under certain conditions, so I took jonrsharpe's advice and moved the definition into __new__ instead:

class Foo(object):
    def __new__(cls):
        cls.bar = property(cls.get_bar)
        return super(Foo, cls).__new__(cls)

    def get_bar(self):
        return "bar"

print(Foo().bar)  #this prints "bar"

However, nothing was gained by this "cleverness". Once the condition was met, the class contained the property. I might as well have defined it as jonrsharpe did.

jcomeau_ictx
  • 36,402
  • 6
  • 91
  • 101