2

I am a Java programmer that is new to Python. I am having trouble understanding the syntax of the following code from the pymodbus repo in GitHub. Where is the function defined?

self.execute(request)

The reason I am confused is that AFAIK self refers to variables and functions of the current class, even inherited ones. There is no function defined in the ModBusClientMixIn class, nor the class inherit from any other class. So where is it coming from?

There is an execute function defined in the ReadCoilsRequest class, but to invoke that why would you need self? Also, where is context(a variable in the execute function argument list) coming from?

Would really appreciate if someone can help me understand the syntax.

ng.newbie
  • 2,807
  • 3
  • 23
  • 57
  • Are you asking why to access attributes/methods you need `self.`? Did you read this question: https://stackoverflow.com/questions/2709821/what-is-the-purpose-of-self ad this one too https://stackoverflow.com/questions/1984104/how-to-avoid-explicit-self-in-python – Giacomo Alzetta Mar 08 '18 at 09:56
  • @GiacomoAlzetta Yes I did read the question about self - but my question is self refers to the current class or the current scope that I am in, and in that scope, there is no execute function defined. Why not just use `obj.execute`, I anyways have a reference to that object. – ng.newbie Mar 08 '18 at 10:01

2 Answers2

3

It's a mixin which is used on classes which do define an execute method, e.g.:

class ModbusClientProtocol(protocol.Protocol, ModbusClientMixin):

A mixin adds methods to other classes and is not supposed to be used by itself.

If you wanted to type-annotate it properly, it would have to be something like:

class Executable(ABC):
    @abstractmethod
    def execute(self):
        pass

class ModBusClientMixin:
    def read_coils(self: Executable, address, count=1, **kwargs):
        #          ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
        # Expects self to conform to Executable interface,
        # i.e. to be used in a class that implements execute().
        self.execute()

Since Python heavily relies on duck-typing and type annotations are a relatively recent addition, they're often omitted and replaced by verbose documentation, or it is expected that developers recognise the purpose of mixins, or that it's such an internal implementation detail that it hasn't been explicitly documented.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • So from what I can understand from your post is that. The execute method is defined in the ModBusClientProtocol, the class ModBusClientProtocol actually adds the method to the ModBusClientMixin class when it is defined. This is pretty weird to me, that I am modifying the behaviour of a particular class from another class never seen this before. – ng.newbie Mar 08 '18 at 10:06
  • Am I correct in my understanding of how the method is declared ? – ng.newbie Mar 08 '18 at 10:06
  • Also then where is the context variable coming from? – ng.newbie Mar 08 '18 at 10:06
  • Python allows multiple inheritance, so one class can inherit methods from multiple parents. `ModBusClientMixin` is used as one such parent, and its purpose is likely largely to reduce code duplication without enforcing a strong class hierarchy. In other languages you have that kind of thing as a *trait*. It is simple that in the end `ModbusClientProtocol` is an amalgamation of both `protocol.Protocol` and `ModbusClientMixin`, combining methods of both classes and adding its own methods. – deceze Mar 08 '18 at 10:09
  • Like I have mentioned in the comment of the other answer - is the execute like an abstract method from java ? – ng.newbie Mar 08 '18 at 10:10
  • Kind of, yes. The inheriting class is *expected* to implement `execute`. It's just not formally annotated. That's what I've tried to illustrate with my code sample. – deceze Mar 08 '18 at 10:11
2

This is a special case. You are right, that execute has to be defined somewhere.

But in this case, execute is implemented by a child class that derives from ModBusClientMixIn.

You would get an error if you were to create an instance of ModBusClientMixIn directly, because it does not implement execute.

Look at the implementations of ModbusClientProtocol or BaseModbusClient for example, they both have an execute method.

Mike Scotty
  • 10,530
  • 5
  • 38
  • 50