Skip to content

Instantly share code, notes, and snippets.

@blaix
Last active August 29, 2015 14:20
Show Gist options
  • Save blaix/3ad853a2b496ac1fb59f to your computer and use it in GitHub Desktop.
Save blaix/3ad853a2b496ac1fb59f to your computer and use it in GitHub Desktop.
Does a @Property with side effects mean "use a method"? I say no, but it does tell us there's a problem with the design.
# Let's say we have a service class:
class Service(object):
def get_article(self, id):
return requests.get('/articles/' + id).json
# For the model, something like this is what we've been doing:
class Article(object):
def init(self, id)
self.id = id
self.data = {}
@cached_property
def title(self):
if not self.data:
self.data = Service().get_article(self.id)
return self.data.get('title')
# I agree with you now that the above is a bad design. `article.title` should
# not have side effects (including network calls). But the argument I've been
# hearing from you is that this means we should use a method and not a
# property. And I don't like that distinction at all. I am thinking about my
# interface and I think Article.title should absolutely be a property. But
# you're right that there's a smell here, it shouldn't require a network hit.
# So I need to rethink my design. I think something like this would be more
# appropriate:
class Article:
def init(**data):
self.data = data
@classmethod
def get_by_id(id):
data = Service().get_article(id)
return Article(**data)
@property
def title():
return self.data.get('title')
# We've introduced a factory method (`get_by_id`) which returns Article objects
# initialized with service data. It's entirely appropriate to expect it to have
# side-effects. So this technically does follow the "properties should not have
# side effects" rule. But I still don't like the bluntness of that. I don't like
# that as an answer to "when should I use a @property vs a method?" I think it
# distracts from larger design decisions. We should think about our interfaces.
# Does this attribute feel like simple data access? Make it a @property. "Ok but
# I wrote it and it it's requiring a service call which is slow / raises
# exceptions / whatever". Ok, continue using a @property, but rethink you're
# design. It sounds like there's work that needs to happen which should not be
# the responsibility of your attribute. Use good OO techniques to come up with a
# better design.
# Which sounds a lot like what you said actually...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment