Snowman
Snowman

Reputation: 32071

Python property not working

I have an object which inherits from ndb.Model (a Google App Engine thing). This object has a property called commentid:

class Comment(ndb.Model):
   commentid = ndb.StringProperty()

Reading a bunch of articles, they all say this is the way to implement a property:

@property
def commentid(self):
   if not self._commentid:
       self._commentid = "1"
   return self._commentid

but I get an error saying Comment object has no attribute _commentid. What am I doing wrong?

Edit: Ok obviously I'm a bit confused here. I come from Objective-C, where if you have a property called x then you automatically get a variable called _x in your getters and setters. So I thought this is what was happening here in Python too. But apparently I need to manually set a value for the variable with an underscore prefix.

All I want is to implement a getter where I do some checking of the value before returning it. How would I do this?

Upvotes: 0

Views: 338

Answers (2)

user1632861
user1632861

Reputation:

Implementing a property like that requires you to define the attribute for your object. What you're doing there, is defining a class called Comment but you don't define any attributes for it's objects, you define them for the class itself.

Let me demonstrate with a small example:

class ExampleClass:
    name = "Example Object"

a = ExampleClass() # Init new instance of ExampleClass
print(a.name) # a doesn't own an attribute called "name"
print(ExampleClass.name) # --> "Example Object"

In the above example, I define class ExampleClass and give it a variable name with a value Example Object. After that, I create an object a = ExampleClass(), however it does not get the name attribute, cause the attribute is defined for the class itself, not for it's objects.

To fix this problem, you define the name inside __init__ -method, which gets called whenever an object of that class is created.

class ExampleClass:
    def __init__(self):
        self.name = "Example Class"

a = ExampleClass() # Init new instance of ExampleClass
print(a.name) # --> "Example Class"
print(ExampleClass.name) # --> ERROR: Exampleclass.name doesn't exist

There I define the ExampleClass again, but I also define __init__ method for it. Init method takes only one parameter, self, which will be automatically given to the function. It's the object which is being created. Then I set self.name = "Example Class", and since self is the object itself, we set the object's attribute name.

Creating the property

To implement setter and getter for your attribute, you add the following:

class ExampleClass:
    def __init__(self):
        self.name = "Example Class"
    
    @property
    def name(self):
        if not self._name:
            pass #blabla code here
        return self._name

    @name.setter
    def name(self, value):
        #blabla more code
        self._name = value

Also, you should edit the __init__ method to take name as a parameter too.

def __init__(self, name="Example Object"):
    self.name = name

Upvotes: 5

user1107907
user1107907

Reputation:

If you access self._commentid directly, it needs to be defined or it'll raise an exception. Since you're instead checking if _commentid is defined at all (to give it a default value), I'd use hasattr:

@property
def commentid(self):
   if not hasattr(self, "_commentid"):
       self._commentid = "1"
   return self._commentid

Upvotes: 2

Related Questions