Search code examples
pythonpython-3.xdecoratorsettergetter-setter

Python setter to also return a value


I was wondering if it would be possible to have a property setter to also return a value. The code below tries to explain superficially the problem.

Basically I need to set a property to an object, but before I need to check if it is unique. I was wondering if there is a way to the return the unique name to the user directly, without needing to query the object for its new name afterwards.

class MyClass(object):
    def __init__(self,ID):
        self._ID = ID
    @property
    def Name(self):
        return DBGetName(self._ID)

    @Name.setter
    def Name(self, value):
        UniqueName = DBGetUniqueName(self._ID,value)
        return DBSetName(UniqueName)

Myinstance = MyClass(SomeNumber)
#What I do now
Myinstance.Name = "NewName"
Uniquename = Myinstance.Name

#What I was wondering if possible. Line below is syntactically invalid, but shows the idea.
Name = (Myinstance.Name = "NewName")

Edit: It is a pseudo code and I forgot to actually pass the value to the inner function. My bad.


Solution

  • A setter certainly can return a value.

    But it isn't very useful to do so, because setters are generally used in assignment statements—as in your example.

    The problem is that in Python, assignment is not an expression, it's a statement. It doesn't have a value that you can use, and you can't embed it in another statement. So, there is no way to write the line you want to write.

    You can instead call the setter explicitly… but in that case, it's a lot clearer to just write it as a regular method instead of a property setter.


    And in your case, I think a regular method is exactly what you want. You're completely ignoring the value passed to the setter. That's going to confuse readers of your code (including you in 6 months). It's not really a setter at all, it's a function that creates a unique name. So, why not call it that?

    def CreateUniqueName(self):
        UniqueName = DBGetUniqueName(self._ID)
        return DBSetName(UniqueName)
    

    (It's worth noting that DBSetName returning its argument is itself not very Pythonic…)


    If you're wondering why Python works this way, see Why can't I use an assignment in an expression? from the official FAQ.

    More generally, the expression-statement distinction, together with associated features like mutating methods (e.g., list.sort) returning None instead of self, leads to a simpler, more regular language. Of course there's a cost, in that it leads to a much less fluent language. There's an obvious tradeoff, and Python is about as far to the extreme as you can get. (Compare to JavaScript, which is about as far to the opposite extreme as you can get.) But most people who love Python think it made the right tradeoff.