Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python mixins how to differentiate same method?

Tags:

python

From here, if you define some objects like that:

class Mixin1(object):
    def test(self):
        print "Mixin1"

class Mixin2(object):
    def test(self):
        print "Mixin2"

class BaseClass(object):
    pass

class MyClass(Mixin2, Mixin1, BaseClass):
    pass

You'll get:

>>> obj = MyClass()
>>> obj.test()
Mixin2

Is there a way to call Mixin1 test() method?

like image 650
Olivier Pons Avatar asked Sep 19 '25 11:09

Olivier Pons


2 Answers

Call it explicitly:

Mixin1.test(obj)

The attribute process in Python is relatively complex. For your given example, this is the process for finding the value of obj.test:

  1. First, look at the instance itself. In this case, the instance does not have a test attribute.
  2. Look at the class which obj is an instance of: MyClass. MyClass does not have a test attribute.
  3. Start looking at the classes in the method resolution order of MyClass. In this case, MyClass.__mro__ tells you to look first at Mixin2, then Mixin1, then object.
  4. Mixin2 has a test attribute, so we finally have a match.
  5. Mixin2.test is a function with a __get__ method, so that is called and the return value is used.

You can safely ignore step 5 here, and just assume that Mixin2.test is a method. One that is returned, you can see that obj.test() calls Mixin2.test.

This might help explain why I asked the question I did in a comment. There is a wide variety of ways you can fiddle with the program to get obj.test() to produce a call to Mixin1.test() instead. You can patch the object, you can fiddle with MyClass.__mro__, you can tweak what Mixin2.test actually does, etc.

like image 53
chepner Avatar answered Sep 21 '25 01:09

chepner


Override the test method and call Mixin1.test explicitly:

class MyClass(Mixin2, Mixin1, BaseClass):
    def test(self):
        Mixin1.test(self)
like image 33
falsetru Avatar answered Sep 21 '25 02:09

falsetru