self参数的使用

2 投票
5 回答
2665 浏览
提问于 2025-04-17 09:09

我刚开始学习Python,对self这个参数有点搞不懂,它是怎么用的,为什么要用它:

class Person:
    def __init__(self, name):
        self.name = name
    def sayHi(self):
        print 'Hello, my name is', self.name

p = Person('Swaroop')
p.sayHi()

这段代码来自《Python小白书》。其实这段代码也可以这样写:

def sayHi(self, name):
            print 'Hello, my name is', name

p = Person('Swaroop')
p.sayHi()

...对吧?那么,把name放到self里面有什么用呢?

5 个回答

2

其实不是的。你的第二个例子是不对的。
‘self’这个关键词是一个特殊的引用,它会传递给类的实例方法。它代表了在那个范围内实际的类实例。当你创建一个类的时候,它只是一个通用的定义。然后你会根据这个类创建实例。每个实例都是独一无二的,因此这些方法必须能够在这个实例上工作。在实例被创建之前,你无法知道它们,所以‘self’会为你传递这些实例。

比如说,如果你创建了两个你的人类实例:

p1 = Person("john")
p2 = Person("sam")

那么这两个实例的self.name的值是不同的。当你在每个实例上调用sayHi()的时候:

p1.sayHi()
> Hello, my name is john
p2. sayHi()
> Hello, my name is sam

你不会在没有绑定的函数中使用self关键词。也就是说,对于你第二个例子中写的那种普通函数,你应该这样写:

def sayHi(name):
        print 'Hello, my name is', name

    p = Person('Swaroop')
    p.sayHi()

> sayHi("john")

但这基本上只是将一个名字字符串传递给Person类,并调用它的方法。这里的意思是你要创建具有自己属性的独特Person实例。

4

看看这个新方法 sayHiTo:

class Person:
    def __init__(self, name):
        self.name = name
    def sayHi(self):
        print 'Hello, my name is', self.name
    def sayHiTo(self, other):
        print 'Hello', other.name, ' my name is', self.name

p1 = Person('Swaroop')
p2 = Person('codeninja')
p1.sayHiTo(p2)
p2.sayHiTo(p1)
6

看起来你把一个并不简单的事情简化得太过了。在面向对象编程中,类(Class)是一个声明性的结构,它提供了一个蓝图,说明一个对象(这个蓝图的具体体现)会包含什么(属性)以及它会如何表现(成员)。每一个这样的类的具体体现叫做对象(Object),它有一个明确的、特定的实例。通过对象的这些行为属性,称为成员函数或方法,我们需要以某种方式引用这个对象的实例,并记住其中的各个元素,同时与其他非成员实体区分开来。

考虑一下你的例子:

class Person:
    def __init__(self, name):
        self.name = name
    def sayHi(self):
        print 'Hello, my name is', self.name

每一个这个人的实例(比如汤姆、迪克、哈里)都是独一无二的。在每个实例中,为了引用它自己,我们需要一些像(Python中的self,C++中的this指针,或者Java中的this)这样的表达方式。

所以在__init__方法中,当你需要区分Person的name属性和name参数时,我们可以很容易地用self来做到这一点。不仅如此,在任何实例中,我们都可以通过self继续引用这个名字。

创建一个Person实例p=Person('Swaroop'),然后调用sayHi,与单纯调用一个不属于对象的sayHi函数相比,有两个不同的含义:

  1. 这个函数是瞬时的,没有状态,没有实例,就像对这个人说:“嘿,先生,不管你是谁,跟我说‘你好,我叫Swaroop’”。就像每次运行时都要让一个傻瓜记住他的名字,而他在下次见面时又会忘记。这就像这个人得了前向性遗忘症。而调用名为Swaroop的Person实例的sayHi,则意味着一个真实存在的Swaroop在回应他的名字,他有持久的记忆,除非他改名,否则永远不会忘记。
  2. 这个函数不会记住任何东西,每次调用结束后就会忘记。而Person对象会记住这个名字,直到你明确或隐含地“杀死”这个人。

如果你有C++的背景,可能会想,为什么在函数调用中需要添加那个额外的参数,而在C++中this指针从来不被传递。其实,坦白说,它是被传递的。如果你阅读C++的调用约定,无论是X86还是X64,this指针是通过寄存器ecx传递给方法,以便给自己一个句柄。在这里我们更明确地将当前实例的句柄传递给方法。

撰写回答