OOP noob question: Mixin properties
mickyhulse.lists at gmail.com
Fri Dec 14 20:01:43 CET 2012
Hi Steven!!! Thanks so much for the pro help, I really do appreciate it. :)
On Thu, Dec 13, 2012 at 4:53 PM, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> Indentation is important. Please don't remove it. I've added it back in
Yikes! Sorry about that. I won't do that again in the future. :(
Thanks for adding the indentation back. :)
> The use of @property here doesn't give you any benefit (except, maybe, if
> you are paid by the line of code). Better to just expose the "cache"
> attribute directly, and likewise for the others. If, in the future, you
> need to turn them into computed properties, you can easily do so. But for
Ah, great to know! Thank you for the clarification, I needed that.
> class JSONResponseMixin(object):
> def __init__(self):
> self.cache = False
> self.cache_timeout = 86400
> self.cache_key = None
> and you're done.
Beautiful! That's nice. Very simple and clean (I had a feeling my
@decorator version was getting a bit "wordy").
>> Simply doing this:
>> class JSONResponseMixin(object):
>> cache = False
>> cache_timeout = 86400 # 24 hours.
>> cache_key = None
>> ...works just as good! Not to mention, it's less verbose.
> In my code above, the cache attributes are defined on a per-instance
> basis. Each instance will have its own set of three cache* attributes. In
> the version directly above, there is a single set of cache* attributes
> shared by all JSONResponseMixin instances.
Thank you for pointing this out! I had not realized that this was the
case. I'm still kinda new to OOP in Python and Python in general (I'm
learning it through Django).
> Will this make any practical difference? Probably not. Most importantly,
> if you write:
> instance = Api() # class includes JSONResponseMixin
> instance.cache = True
> then the assignment to an attribute will create a non-shared per-instance
> attribute which overrides the class-level shared attribute. This is
> almost certainly the behaviour that you want. So this is a good example
> of using class attributes to implement shared default state.
Whoa, that's cool!
> There is one common place where the use of shared class attributes can
> lead to surprising results: if the class attribute is a mutable object
> such as a list or a dict, it may not behave the way you expect. That is
> because only *assignment* creates a new per-instance attribute:
> instance.attribute = "spam spam spam" # overrides the class attribute
> while modifying the attribute in place does not:
> instance.shared_list.append("spam spam spam")
> # every instance of the class will now see the change
Exactly the type of details I was hoping to learn. Thank you so much
for taking the time to explain things in such detail and easy to
understand way. I really appreciate it. :)
> Apart from that Gotcha, the use of shared class attributes to implement
> default behaviour is perfectly acceptable.
Awesome! That's good to know.
> I actually prefer a functional response, up to the point where I'm
> passing so many arguments to functions that I can't keep track of what's
> what. Then I refactor into a class.
Ah, well that's good to know. There's a part of me that wants to
revert back to passing arguments to self.render_to_response(...);
after all, there's only 3 of them. On the flip side, if I hadn't
explored other options, I wouldn't have learned anything new.
Thanks a billion Steven! I owe you one.
Have a great holiday.
More information about the Python-list