Reputation: 705
I have a class like this:
class MyItem:
def __init__(self):
self.person = None
self.place = None
self.thing = None # property
However I also want to define a property for one of the attributes, for example:
@property
def thing(self):
return self.person + self.place
In other words, I want to make my initialization show all my variables so it's explicit, but I want to "override" one of those attributes with a class property. How would I do this?
As an example of what I currently have:
class MyItem:
def __init__(self):
self.person = None
self.place = None
self.thing = None # property
@property
def thing(self):
return self.person + self.place
m=MyItem()
m.person='A'
m.place='B'
print m.thing
>>> None
Upvotes: 2
Views: 307
Reputation: 8122
Maybe this isn't the answer you're looking for, but my advice:
Don't define MyItem.thing
in more than one place.
That would be confusing and probably give you heartburn in the long run. And the short run.
The thing is that MyItem.__init__()
is not documentation, it's just defining how instantiation happens. Documentation is documentation and unfortunately it is a bit of a hassle to write sometimes. Have a look at sphinx
's autodoc
and/or the pdoc3
project to see how these tools can write your docs for you, based on your classes, properties, methods, etc.
Here's how I would do it:
class MyItem:
"""
Defines an item.
Attributes
----------
person: A person.
place: A place.
Properties
----------
thing: A thing, the sum of person and place.
Methods
-------
There aren't any, but there will be!
"""
def __init__(self, person=None, place=None):
self.person = person
self.place = place
@property
def thing(self):
"""
Property of MyItem instance. The sum of person and place,
if both of those things exist.
Returns
-------
str. The sum of the person and place attributes.
"""
if (self.person is not None) and (self.place is not None):
return self.person + self.place
else:
return None
m = MyItem('A', 'B')
print(m.thing)
This returns:
'AB'
I'd also start using Python 3 as soon as possible.
Upvotes: 1
Reputation: 95948
There are two things wrong here. Firstly, your code as written is allowing the shadowing of a property by an instance attribute because you are on Python 2 and have not inherited from object, the descriptor protocol requires new-style classes to work properly. So, note what happens when we do this:
class MyItem(object):
def __init__(self):
self.person = None
self.place = None
self.thing = None # property
@property
def thing(self):
return self.person + self.place
m=MyItem()
m.person='A'
m.place='B'
print m.thing
The output should be:
Traceback (most recent call last):
File "test.py", line 10, in <module>
m=MyItem()
File "test.py", line 5, in __init__
self.thing = None # property
AttributeError: can't set attribute
Which is what we should expect, since we haven't created a setter. I would argue this is the behavior you would want. However, there is nothing stopping you from implementing a setter that simply does nothing:
class MyItem(object):
def __init__(self):
self.person = None
self.place = None
self.thing = None # property
@property
def thing(self):
return self.person + self.place
@thing.setter
def thing(self, val):
pass
m=MyItem()
m.person='A'
m.place='B'
print m.thing
Which now ouputs:
AB
Although, I consider this an example of failing silently in a way that will probably cause headaches down the road. I would strongly advise against doing this, but it's possible.
Upvotes: 2