31

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?

5
  • 2
    Why would you like to use different name? Is there a reasonable reason? Commented Feb 16, 2014 at 14:01
  • 1
    Have you tried using property as a decorator or with a docstring? Commented Feb 16, 2014 at 14:02
  • A quick solution will be to call __get__ on bar explicitly: f = Foo();f.bar.__get__(f, type(f)) Commented Feb 16, 2014 at 14:16
  • 14
    (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) Commented Sep 9, 2015 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! Commented Mar 2, 2018 at 15:21

6 Answers 6

23

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.

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

5 Comments

I was defining the property before the function. All okay now.
@gcq Now, try and set the value of bar.
Why does the output of property work differently if it's bar = property() at the top level vs. self.bar = property() within __init__?
@EL_DON because the property needs to be an attribute of the class, not the instance; that's how the descriptor protocol works.
@jonrsharpe Thanks. Maybe put that in the answer?
9

The object is not instantiated.

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

2 Comments

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.
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...
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 

Comments

7

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.

Comments

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.

Comments

0

Do the following if you want to do within init()

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

The property method is basically similar to property decoration, it tells python to define a property.

And then we assign this to "bar" property of the type. This needs to be at the type level because you are defining the property for the class, so it is static, not a specific instance.

get_bar is your usual getter where you use the decorator.

1 Comment

While this code snippet may be the solution, including a detailed explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.