Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login

With interfaces, the above example would look like this:

    from abc import ABCMeta   

    class PhysicsobjectMixin(ABCMeta):
        @abstractmethod
        def update_physics(self):
            pass
        
        @abstractmethod
        def apply_konckback(self, force):
            pass

        @abstractmethod
        def get_position(self):
            pass


    class FightMixin(ABCMeta):
        @abstractmethod
        def attack(self):
            pass

        @abstractmethod
        def defend(self):
            pass

    
    class TalkMixin(ABCMeta):
        @abstractmethod
        def say_something(self):
            pass


    class Character(PhysicsobjectMixin, FightMixin, TalkMixin):
        def update_physics(self):
            pass

        def apply_konckback(self, force):
            pass

        def get_position(self):
            pass

        def attack(self):
            pass

        def defend(self):
            pass

        def say_something(self):
            pass


    class Pickup(PhysicsobjectMixin):
        def update_physics(self):
            pass
        
        def apply_konckback(self, force):
            pass

        def get_position(self):
            pass


    class Projectile(PhysicsobjectMixin):
        def update_physics(self):
            pass
        
        def apply_konckback(self, force):
            pass

        def get_position(self):
            pass

This is not DRY at all. I like mixins much better.


sort by: page size:

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

1: https://pynecone.io/docs/state/overview


> 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.)

    class Projectile(object):
        def update_physics(self):
            pass
        
        def apply_konckback(self, force):
            pass

        def get_position(self):
            pass

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.

>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.

Except then your method shares a namespace with all the other methods defined on the class, which is ugly, and can cause clashes.


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).

You can do cool nested calls with them too.

    >>> class A:
    ...     def __init__(self):
    ...         self.foo = 5
    ...     def bar(self):
    ...         return 'cake'
    ...
    >>> a = A()
    >>> f'{a.foo}'
    '5'
    >>> f'{a.bar()}'
    'cake'

    >>> x = {'b': 1, 'c': 2}
    >>> f"{x['b']}"
    '1'

#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 is not pythonic in any way shape of form.


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.


Ironically, in Python you can use interfaces without ever resorting to inheritance. :)

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.

Right, but there's more to classes in Python than just methods (inheritance etc.).

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.


I'm aware of that but that's what people call a hack, don't act like it's not. Python doesn't support abstract classes, period.

Python sort of has multimethods, but only for type-annotations, not for actually dispatching to code.
next

Legal | privacy