在Python中定义类的方法时,它看起来像这样:

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

但是在其他一些语言中,比如c#,你有一个对象的引用,这个对象是用"this"关键字绑定的,而不是在方法原型中作为参数声明的。

这是Python中有意的语言设计决策,还是有一些实现细节需要传递“self”作为参数?


这是为了最小化方法和函数之间的差异。它允许您轻松地在元类中生成方法,或在运行时向已存在的类添加方法。

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!
>>>

它还(据我所知)使python运行时的实现更容易。


我喜欢引用彼得斯的《Python禅》。“明确的比含蓄的好。”

在Java和c++中,'this。'可以被推导出来,除非你的变量名使它无法推导。所以你有时需要它,有时不需要。

Python选择显式地做这样的事情,而不是基于规则。

此外,由于没有隐含或假设任何内容,部分实现将被公开。自我。__class__进行自我。__dict__和其他“内部”结构可以以一种明显的方式使用。


还有另一个非常简单的答案:根据python的禅宗,“显式比隐式好”。


Python不会强制你使用"self"。你可以给它起任何你想要的名字。你只需要记住方法定义头中的第一个参数是对对象的引用。


我建议大家应该读读Guido van Rossum关于这个话题的博客——为什么外显的自我必须留下来。

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'.


我认为这和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.


也允许你这样做:(简而言之,调用Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5)将返回12,但将以最疯狂的方式这样做。

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

当然,这在Java和c#等语言中很难想象。通过使自引用显式,您可以自由地通过该自引用引用任何对象。而且,这种在运行时处理类的方式在静态语言中更难做到——这并不是说它一定是好是坏。只是外显的自我允许所有这些疯狂的存在。

此外,想象一下:我们想要定制方法的行为(用于分析,或一些疯狂的黑魔法)。这可能会导致我们思考:如果我们有一个类Method,我们可以重写或控制它的行为呢?

就是这样:

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()

现在:InnocentClass().magic_method()将像预期的那样工作。该方法将与innocent_self参数绑定到InnocentClass,与magic_self绑定到MagicMethod实例。奇怪的是吧?这就像在Java和c#等语言中有两个关键字this1和this2。像这样的魔术允许框架做一些事情,否则会非常冗长。

再说一次,我不想评论这些东西的道德性。我只是想展示一些如果没有显式的自我引用就很难做到的事情。


我认为除了“Python之禅”之外,真正的原因是函数是Python中的第一类公民。

这本质上使它们成为对象。最基本的问题是如果你的函数也是对象那么在面向对象的范例中当消息本身是对象时你将如何向对象发送消息?

看起来像一个先有鸡还是先有蛋的问题,为了减少这种矛盾,唯一可能的方法是将执行上下文传递给方法或检测它。但是由于python可以有嵌套函数,因此不可能这样做,因为内部函数的执行上下文会发生变化。

这意味着唯一可能的解决方案是显式传递'self'(执行上下文)。

所以我认为这是一个执行问题,禅宗来得晚了很多。


正如Python中的self所解释的那样,Demystified

任何类似obj.meth(args)的东西都会变成Class。甲安菲他明(obj, args)。调用进程是自动的,而接收进程不是(它的显式)。这就是类中函数的第一个形参必须是对象本身的原因。

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

调用:

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

init()定义了三个参数,但我们只传递了两个(6和8)。同样,distance()需要一个参数,但传递了0个参数。

为什么Python没有抱怨这个参数号不匹配?

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.

自我在这里停留 许多人建议在Python中使self成为关键字,就像在c++和Java中那样。这将消除方法中形式参数列表中显式self的冗余使用。虽然这个想法看起来很有希望,但它不会发生。至少近期不会。主要原因是向后兼容。下面是Python创建者自己的一篇博客,解释了为什么显式自我必须保留。


self形参保存当前调用对象。

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

在这里,self参数保存对象obj。因此,语句self。Var表示obj.var