Why do you need explicitly have the "self" argument in a Python method?

PythonOopMethodsSelf

Python Problem Overview


When defining a method on a class in Python, it looks something like this:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

But in some other languages, such as C#, you have a reference to the object that the method is bound to with the "this" keyword without declaring it as an argument in the method prototype.

Was this an intentional language design decision in Python or are there some implementation details that require the passing of "self" as an argument?

Python Solutions


Solution 1 - Python

I like to quote Peters' Zen of Python. "Explicit is better than implicit."

In Java and C++, 'this.' can be deduced, except when you have variable names that make it impossible to deduce. So you sometimes need it and sometimes don't.

Python elects to make things like this explicit rather than based on a rule.

Additionally, since nothing is implied or assumed, parts of the implementation are exposed. self.__class__, self.__dict__ and other "internal" structures are available in an obvious way.

Solution 2 - Python

It's to minimize the difference between methods and functions. It allows you to easily generate methods in metaclasses, or add methods at runtime to pre-existing classes.

e.g.

>>> class C:
...     def foo(self):
...         print("Hi!")
...
>>>
>>> def bar(self):
...     print("Bork bork bork!")
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

It also (as far as I know) makes the implementation of the python runtime easier.

Solution 3 - Python

I suggest that one should read Guido van Rossum's blog on this topic - Why explicit self has to stay. > When a method definition is decorated, we don't know whether to automatically give it a 'self' parameter or not: the decorator could turn the function into a static method (which has no 'self'), or a class method (which has a funny kind of self that refers to a class instead of an instance), or it could do something completely different (it's trivial to write a decorator that implements '@classmethod' or '@staticmethod' in pure Python). There's no way without knowing what the decorator does whether to endow the method being defined with an implicit 'self' argument or not. > > I reject hacks like special-casing '@classmethod' and '@staticmethod'.

Solution 4 - Python

Python doesn't force you on using "self". You can give it whatever name you want. You just have to remember that the first argument in a method definition header is a reference to the object.

Solution 5 - Python

Also allows you to do this: (in short, invoking Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5) will return 12, but will do so in the craziest of ways.

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

Of course, this is harder to imagine in languages like Java and C#. By making the self reference explicit, you're free to refer to any object by that self reference. Also, such a way of playing with classes at runtime is harder to do in the more static languages - not that's it's necessarily good or bad. It's just that the explicit self allows all this craziness to exist.

Moreover, imagine this: We'd like to customize the behavior of methods (for profiling, or some crazy black magic). This can lead us to think: what if we had a class Method whose behavior we could override or control?

Well here it is:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)
    
    
    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs
        
class InnocentClass(object):
    magic_method = MagicMethod()

And now: InnocentClass().magic_method() will act like expected. The method will be bound with the innocent_self parameter to InnocentClass, and with the magic_self to the MagicMethod instance. Weird huh? It's like having 2 keywords this1 and this2 in languages like Java and C#. Magic like this allows frameworks to do stuff that would otherwise be much more verbose.

Again, I don't want to comment on the ethics of this stuff. I just wanted to show things that would be harder to do without an explicit self reference.

Solution 6 - Python

I think it has to do with PEP 227:

> Names in class scope are not accessible. Names are resolved in the > innermost enclosing function scope. If a class definition occurs in a > chain of nested scopes, the resolution process skips class > definitions. This rule prevents odd interactions between class > attributes and local variable access. If a name binding operation > occurs in a class definition, it creates an attribute on the resulting > class object. To access this variable in a method, or in a function > nested within a method, an attribute reference must be used, either > via self or via the class name.

Solution 7 - Python

I think the real reason besides "The Zen of Python" is that Functions are first class citizens in Python.

Which essentially makes them an Object. Now The fundamental issue is if your functions are object as well then, in Object oriented paradigm how would you send messages to Objects when the messages themselves are objects ?

Looks like a chicken egg problem, to reduce this paradox, the only possible way is to either pass a context of execution to methods or detect it. But since python can have nested functions it would be impossible to do so as the context of execution would change for inner functions.

This means the only possible solution is to explicitly pass 'self' (The context of execution).

So i believe it is a implementation problem the Zen came much later.

Solution 8 - Python

As explained in self in Python, Demystified

>anything like obj.meth(args) becomes Class.meth(obj, args). The calling process is automatic while the receiving process is not (its explicit). This is the reason the first parameter of a function in class must be the object itself.

class Point(object):
    def __init__(self,x = 0,y = 0):
        self.x = x
        self.y = y

    def distance(self):
        """Find distance from origin"""
        return (self.x**2 + self.y**2) ** 0.5

Invocations:

>>> p1 = Point(6,8)
>>> p1.distance()
10.0

init() defines three parameters but we just passed two (6 and 8). Similarly distance() requires one but zero arguments were passed.

Why is Python not complaining about this argument number mismatch?

>Generally, when we call a method with some arguments, the corresponding class function is called by placing the method's object before the first argument. So, anything like obj.meth(args) becomes Class.meth(obj, args). The calling process is automatic while the receiving process is not (its explicit).

This is the reason the first parameter of a function in class must be the object itself. Writing this parameter as self is merely a convention. It is not a keyword and has no special meaning in Python. We could use other names (like this) but I strongly suggest you not to. Using names other than self is frowned upon by most developers and degrades the readability of the code ("Readability counts").
...
In, the first example self.x is an instance attribute whereas x is a local variable. They are not the same and lie in different namespaces.

>## Self Is Here To Stay Many have proposed to make self a keyword in Python, like this in C++ and Java. This would eliminate the redundant use of explicit self from the formal parameter list in methods. While this idea seems promising, it's not going to happen. At least not in the near future. The main reason is backward compatibility. Here is a blog from the creator of Python himself explaining why the explicit self has to stay.

Solution 9 - Python

The 'self' parameter keeps the current calling object.

class class_name:
    class_variable
    def method_name(self,arg):
        self.var=arg 
obj=class_name()
obj.method_name()

here, the self argument holds the object obj. Hence, the statement self.var denotes obj.var

Solution 10 - Python

There is also another very simple answer: according to the zen of python, "explicit is better than implicit".

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionreadonlyView Question on Stackoverflow
Solution 1 - PythonS.LottView Answer on Stackoverflow
Solution 2 - PythonRyanView Answer on Stackoverflow
Solution 3 - PythonbhadraView Answer on Stackoverflow
Solution 4 - PythonVictor NoagbodjiView Answer on Stackoverflow
Solution 5 - Pythonvlad-ardeleanView Answer on Stackoverflow
Solution 6 - PythondaoleView Answer on Stackoverflow
Solution 7 - PythonpankajdohareyView Answer on Stackoverflow
Solution 8 - PythonmonView Answer on Stackoverflow
Solution 9 - PythonSanmitha SadhishkumarView Answer on Stackoverflow
Solution 10 - PythonFlávio AmieiroView Answer on Stackoverflow