Looking at some of the examples in the docs [1]. Seems very odd that the mixin class they provided essentially lets you use bounded/instance variables and methods as class attributes and class method. Nevertheless, this seems very promising and I'm happy someone spent time on this
> For example, what if you want to add custom animations any time your `Character` takes an action?
What's wrong with this?
class Character(PhysicsobjectMixin, FightMixin, TalkMixin):
def attack(self):
# custom attack animation here
return super(Character, self).attack()
def defend(self):
# custom defend animation here
return super(Character, self).defend()
For me, it's still clear that 'attack' and 'defend' extends the funcionality of the 'FightMixin'. I can see even the first glance, those are inherited methods, because they use super() (call parent methods)
> How about if your physics for a `Projectile` are different than for a `Pickup`?
You need to implement two classes anyway. I see two possibilities:
I. If you have to implement this kind of different physics behavior only for Projectile. (Maybe you don't even need a mixin.)
II. If you have more Projectile-like objects, but they are not all the same.
class FastMovingPhysicsobjectMixin(object):
def update_physics(self):
pass
def apply_konckback(self, force):
pass
def get_position(self):
pass
class Projectile(FastMovingPhysicsobjectMixin):
pass
class Arrow(FastMovingPhysicsobjectMixin):
pass
> What if your character suddenly picks up a Sling of Thrown Voices, and needs to apply conversation snippets to its projectiles?
Is this a weapon which doesn't shoot projectiles, but make damage with voice or what? :D
Then I think it's totally different, because if Character can have all kinds of different weapons and those behave different ways, mixins don't fit here. I would rather implement that like this:
class Sword(object):
def attack(self):
# swing
def defend(self):
# defend
class SlingOfThrownVoices(object):
def attack(self):
# shout loudly
def defend(self):
# pssszt, be quiet
class Character(PhysicsobjectMixin, TalkMixin):
def __init__(self, weapon):
self.weapon = weapon
def attack(self):
# custom attack animation here
self.weapon.attack()
def defend(self):
# custom defend animation here
self.weapon.defend()
then weapon can be instance of either Sword or SlingOfThrownVoices. Note that Mixins are still in use and no complicated inheritance problem occured even if you have hundreds of weapons.
I think the thing I'd miss most from python if I was using this is multiple-inheritance. Not even necessarily true multiple inheritance, but at least some kind of mixin.
That's a pattern that I've seen a lot in Javascript, where it's usually called a "mixin" and used as pseudo-inheritance. I'm not sure why you would do it in Python.
This is, I think, largely a result of Python not idiomatically using mixins as much as Ruby (since it has multiple inheritance, it supports them, and they are sometimes used, but Ruby leans into them hard in the core.)
In the Ruby way, with otherwise similar setup, you would have a mixin that provided __iter__() given __len__() and __getitem__(), and classes that had the last two but wanted the behavior of the first would just include that mixin class as a parent, rather than having a separate branch in iter() to handle the different cases. (Ironically, its one way that Ruby is less TMTOWTDI than Python is.)
I don't know exactly for Python. I would expect mixin class to be used for this. Also, maybe Python will allow you to define union types: e.g. X is either a "foo", a "bar" or a "zot" (all of them duck types the same implicit interface).
#1 the correct way to do it is to have the methods perform the same action on mutable and immutable objects.
this is the only way to guarantee composition. you do not change the semantics of shared methods.
#2
for both of these examples you give 'to use whatever you want'
"".join(['a','b']) is how everyone else does it in python code.
it isn't about things in the community being usable within your library, it is about your library being /unusable/ within the community. You re-invent new and awkward ways to do standard things without standard idioms.
'i've just invented a whole bunch of new semantics for things so it will be readable'
readability is about /convention/. readable to whom? pushing your own love of jquery method chaining only serves to ostracise those already somewhat knowledgable within python.
It’s basically as complicated as “If a subclass and a parent class both define a `bar()` method, and you have an instance of the subclass named `foo`, calling `foo.bar()` will call the subclass version”
I actually find that simpler than some of the spaghettis you can create with Python’s multiple inheritance :P
Ostensibly, Python has a more Java-like model of method invocation, but this is really only a semantic difference. There is little that you can do with Python methods that you can't do with Ruby's methods and vice-versa.
Generally, checking the type with isinstance is considered bad practice although it can be useful sometimes (I can't think of any simple examples off the top of my head though).
The main reason I can think of for using an interface or abc is simply so that if you forget to add a required method, the exception gets thrown sooner rather than later. Plus with an abc, you also allow the base class to define methods that depend upon abstract methods (for instance, if you subclass the Mapping abc, you get __contains__, keys, items, etc for adding __getitem__). Strictly speaking, there's no reason why you can't do that without an abstract base class, but it makes it easier.
In short, there are useful reasons to have interfaces and abstract base classes in Python, but they probably aren't the same reasons you'd want them in a statically-typed language like Java.
If I understand the PEP right, this explanation is missing the part where it's only useful to extend abstract classes; python classes are open so you can just add a method to a concrete class to get single-dispatch if that's all you need. I don't think the example given needs generics at all.
But Python's methods already have self curried in. Class.foo(self, x) takes two arguments, but instance.foo(x) already has self bound, and only takes on argument.
This lets you do bar = instance.foo; bar(x) and it'll still work. Much more consistent.
> The tradeoff is that you don't get to have open classes with a module oriented approach.
A module oriented approach could still have open classes, and if you did an imported module could still mess with classes in other imported modules (it would just also have to import them.)
In fact, you can set variables in other modules and members (including methods) of other classes this way in Python.
> tying methods with the individual/first argument makes it very difficult to model interactions of multiple objects.
The best example of this in Python is operator overloading. We need to define both `__add__` and `__radd__` methods to overload a single operator. Even then, there are situations where Python will call one of those where the other would be better.
reply