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

前端 未结 10 1267
借酒劲吻你
借酒劲吻你 2020-11-22 11:53

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
        se         


        
相关标签:
10条回答
  • 2020-11-22 12:34

    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(object):
    ...     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.

    0 讨论(0)
  • 2020-11-22 12:34

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

    0 讨论(0)
  • 2020-11-22 12:44

    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.

    0 讨论(0)
  • 2020-11-22 12:51

    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.

    0 讨论(0)
提交回复
热议问题