Reputation: 2488
So, I have this code snippet.
class LogObserver(object):
def write_log(...):
self.logger.log(self, level, message, *args, **kwargs)
...
Looking into the debugger and the error messages as well, I noticed that the variable level
contains LogObserver
instead of an integer. I was expecting an integer.
However, when I remove self
from self.logger.log()
like:
self.logger.log(level, message, *args, **kwargs)
level
contains an integer instead of a LogObserver
object. The error messages disappear as well.
What is the explanation behind this behavior?
Upvotes: 0
Views: 60
Reputation: 52139
If you call an instance method (not staticmethod or classmethod), the instance is implicitly passed as the first parameter. That is why method definitions take self
as the first parameter; the name self
is just a convention, by the way. For example, foo.bar()
will be translated to type(foo).bar(foo)
.
If you explicitly pass on the instance as an argument, it will be passed along like any other argument - after the instance is passed in implicitly already. For example, foo.bar(foo)
will be translated to type(foo).bar(foo, foo)
.
Now, inside a method, self
is usually the first parameter. Let's say you have defined
class Foo(object):
def bar(self, other=None):
pass
foo = Foo()
Calling foo.bar()
is translated to type(foo).bar(self=foo, other=None)
.
Likewise, foo.bar(foo)
is translated to type(foo).bar(self=foo, other=foo)
.
So, when you call self.logger.log(self, level, message, *args, **kwargs)
, that actually translates to type(self).logger.log(self=self, level=self, message=level, args=(message,), kwargs={})
. Thus, level
gets an instance of your object, namely self
.
Note that foo.bar()
is not always resolved as type(foo).bar(foo)
- this is only the case if bar
is only defined on the class/type. The passing of self
is not changed by this, however.
Upvotes: 3