5

I am trying to use a property setter as below. I'm following the example here: How does the @property decorator work?

class Contact:
    def __init__(self):
        self._funds = 0.00

    @property
    def funds(self):
        return self._funds

    @funds.setter
    def funds(self, value):
        self._funds = value

The getter works fine

>>> contact = Contact()
>>> contact.funds
0.0

but I'm missing something about the setter:

>>> contact.funds(1000.21)

Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/doctest.py", line 1315, in __run
    compileflags, 1) in test.globs
  File "<doctest __main__.Contact[2]>", line 1, in <module>
    contact.funds(1000.21)
TypeError: 'str' object is not callable

What am I doing wrong here?

Mark Irvine
  • 1,349
  • 14
  • 24

2 Answers2

10

Just use the contact.funds = 1000.21 syntax. It will set it using @funds.setter.

I cannot reproduce your 'str' object is not callable error, rather I get a 'float' object is not callable error. More detail on how it is being run would be helpful for diagnosing that. Regardless, the reason is that contact.funds will give you back the value of contact._funds, which is not a callable object, hence the error.

MoxieBall
  • 1,907
  • 7
  • 23
  • This doesn't answer his question as to what he is doing wrong here – APorter1031 Jun 26 '18 at 16:54
  • 2
    @APorter1031 While I thought the answer to the question was self-explanatory, I have updated my answer to reflect this. – MoxieBall Jun 26 '18 at 17:00
  • @MoxieBall, sorry I was simplifying the code to boil it down to the simplest form. I was modifying the string before returning. I took out that and changed it to an int but never updated the error message. Thanks for providing the answer. – Mark Irvine Jun 26 '18 at 17:32
4

@MoxieBall and @pavan have already shown the syntax. I'll dive in a bit deeper to help explain what's going on.

The @property decorator exists precisely so you can get and set object fields via the convenient x = object.field and object.field = value syntax. So @MarkIrvine, you've done everything correctly to enable your contact.funds() getter to become contact.funds and your contact.funds(value) setter to become contact.funds = value.

The confusion lies in the fact that the @property decorator re-defines the symbols in your contact objects. In other words, contact.funds is a Descriptor object. Once you've applied the @funds.setter decorator to def funds(self, value):, the funds function no longer exists as you defined it. So contact.funds(value) first returns the contact.funds property, then tries to call it as if it were a function.

Hope that helps. =)

tankthinks
  • 973
  • 6
  • 9