ahal / hunting-the-shmoo

My personal blog
0 stars 0 forks source link

blog/2014/when-would-you-use-python-mixin/ #384

Open ahal opened 4 years ago

ahal commented 4 years ago

https://ahal.ca/blog/2014/when-would-you-use-python-mixin/

ahal commented 4 years ago

Screwtape wrote on 2014-05-24 07:53:26

A good example of mixins in Python would be the "collections.abc" module in the standard library. For example, if you implement __getitem__() and __len__() then inherit from collections.abc.Sequence, you automatically get implementations of __contains__(), __iter__(), __reversed__(), index() and count() methods. If you used composition, you would have to manually define each of those methods to call the equivalent method on your internal Sequence object, which is certainly possible but also pretty tedious.

ahal commented 4 years ago

Jj wrote on 2014-05-24 07:58:08

Depends on your need, not always coding is a perfect abstraction of reality. Classes and objects don't always represent real world entities with real world relationships.

I've found myself using mixins to extend funcionality, to provide base classes. I use Django a lot and using Forms, Views, Admin classes, mixins are a great tool to have. When having a set of related views, if you know the methods you can just write your own and a few helpers and save yourself a lot of coding just by defining classes that inherit from framework provided classes and your mixins, declare a couple of class attributes as configuration and be good to go.

ahal commented 4 years ago

William Lachance wrote on 2014-05-24 14:48:32

Yes, I think it just comes down to the fact that sometimes mixins are an easier way to get the behaviour that you want when expressing concepts that can't simply be defined as "A is a B" or "A has a B". Screwtape's example is good, another one that comes to mind in our code is the droid mixin we use in mozdevice for adding Android-specific functionality to DeviceManager:

http://mxr.mozilla.org/mozi...

For each implementation (ADB and SUT) we want a base class without the functionality, so a mixin is the best way of generating a new classes with the desired methods.

You are right about the gotchas though. In general I have found inheritance to not always work how I expect in Python and that includes Mixins. I guess that's the price you pay for its expressiveness vs. (e.g.) Java.

ahal commented 4 years ago

ahal wrote on 2014-05-24 19:21:07

Yeah, that is a good example, never really occurred to me.

ahal commented 4 years ago

ahal wrote on 2014-05-24 19:23:14

"If you know the methods" is the catch there in my opinion. You might know the methods, but someone else reading your code doesn't. I guess if you are working on something you know no one else will ever have to maintain it, then it doesn't really matter.

ahal commented 4 years ago

ahal wrote on 2014-05-24 19:32:00

Personally I think self.fennec.launch() is easier to understand than self.launch_fennec() in that case. But I guess that does show that it comes down to personal preference. The example you linked is really clear, but I've seen what happens when mixins get abused. And yes, it is possible to abuse composition as well :)

ahal commented 4 years ago

William Lachance wrote on 2014-05-24 21:43:12

I don't think your alternative implementation really makes sense. What would the fennec object represent? All we're doing is providing an interface to the Android "launch" mechanism, which properly belongs in the devicemanager class.

ahal commented 4 years ago

Jj wrote on 2014-05-25 04:22:48

That's a different point point. The case is that for those situations Mixins can be pretty helpful. Yes I didn't know the methods, but I read the docs and then I knew them. It's learning an interface just like any other library, you have to learn how to use it. It's not like methods in code are secrets.

ahal commented 4 years ago

ahal wrote on 2014-05-26 13:38:36

Definitely :). Good documentation goes a long way, but unfortunately good documentation is often a luxury. With composition it is easy to see which attributes come from which class by reading the code, there is no ambiguity. It is also easy for a small number of mixins. But when a class has 3+ mixins, it becomes a real pain to hunt down which attributes belong to which mixins.

washad commented 4 years ago

Late to the game, but I came upon this;

Think about the example of composition from the perspective of someone using the class (even if it is you). When you force "t.index.search(....)" 1: You've consumed an additional mental register in the statement (Millers Law - Magic number 7) 2: You've forced the user to know that your class has an index field 3: You've tightly coupled your code to the index object (Law of Demeter) 4: You've forced future refactor to search on something other than index;

If you user; t.search(...), however; 1: Zero mental registers (you already know what search means) - it is well aliased 2: No need to look further into your class 3: You've reduced coupling 3: If you later want to search by title or some other field, you can simply change the Mixin

Granted, you could (an should) abstract out search by wrapping it at your class level such that "index.search()" is called behind the scenes -- a reasonable approach, but what if your mixin provides lost of additional features (not just search), and you use those features in a lot of places. Think of how many additional properties or methods you might have to write?

Other languages don't allow multiple inheritance (e.g. C#) so mixins are not an option in the Python sense -- and what you often see is a crap load of interfaces written to deal with these problems.