“自我”一词的目的是什么?


1129

selfPython 中的单词的目的是什么?我知道它是指从该类创建的特定对象,但是我看不到为什么要将它显式地作为参数添加到每个函数中。为了说明这一点,在Ruby中,我可以这样做:

class myClass
    def myFunc(name)
        @name = name
    end
end

我很容易理解。但是在Python中,我需要包括self

class myClass:
    def myFunc(self, name):
        self.name = name

有人可以通过这个告诉我吗?我的经历(公认有限)并不是我遇到的。


111
:您可能会感兴趣的这篇文章“为什么要明确自己已经留”由Guido van Rossum的neopythonic.blogspot.com/2008/10/...
unutbu

14
另请参见“为什么要‘自我’进行明确方法定义和调用中使用”:docs.python.org/faq/...
unutbu

37
“我很理解,很容易理解” ---很主观,您不觉得吗?有什么@name比这更直观的self.name呢?后者,IMO,更加直观。
圣诞老人

14
那是函数和类方法之间的关键区别。一个函数可以自由浮动,不受阻碍。一个类(实例)方法必须知道它的父类(和父属性),因此您需要向该方法传递对父类的引用(如self)。这只是在理解OOP之前必须内部化的较少隐性规则。其他语言选择语法糖而不是语义简单性,python不是其他语言。
Evan Plaice 2012年

9
我认为“明确胜于隐含”并不能很好地解释这种设计选择。 @foo并且self.foo同样是显式的,因为不需要进行任何隐式的解析(例如,在C ++中,可以使用名称空间“隐式”访问实例成员,而无需“显式”访问实例成员)。唯一的区别是Ruby引入了新的语义(@),而Python没有。一种新的语义是否值得避免的冗长程度纯粹是主观的。不过,应该指出的是,大多数现代语言都选择在此处引入一个概念(例如php的$ this,JS的this)。

Answers:


710

需要使用的原因self.是因为Python不使用@语法来引用实例属性。Python决定以一种使该方法所属的实例自动传递但不会自动接收的方式进行方法:方法的第一个参数是调用该方法的实例。这使方法与函数完全相同,并保留实际名称供您使用(尽管self是约定俗成的,当您使用其他方法时,人们通常会皱着眉头。)self对于代码而言并不特殊,它只是另一个对象。

Python可以做一些其他事情来区分普通名称和属性-像Ruby这样的特殊语法,或者像C ++和Java这样的声明都需要,或者也许还有其他不同-但事实并非如此。Python的全部目的是使事情变得明确,使事情变得显而易见,尽管它并非在所有地方都做到这一点,但它确实为实例属性做到了。因此,分配给实例属性需要知道要分配给哪个实例,这就是为什么需要的原因self.


23
@Georg:cls引用类对象,而不是实例对象
SilentGhost 2010年

17
@SilentGhost:实际上,第一个参数的名称就是您想要的名称。在类方法上,将使用约定,cls并且self惯例通常用于实例方法。如果需要的话,可以self用于类方法和cls实例方法。我还可以使用bobfnord,如果我喜欢。
SingleNegationElimination

67
我发现社区没有选择this而是选择了,这很有趣self。是否self有一些较旧的编程语言我不知道的历史记录?
Jules GM

24
@Julius self来自Modula-3的约定,有关此选择的更多详细信息,请参见此答案。(免责声明:它是我的)。
Bakuriu

9
@Julius self关键字(Smalltalk,1980年)早于this关键字(来自C ++)。请参阅:stackoverflow.com/questions/1079983/...
韦斯·特纳

425

让我们看一个简单的向量类:

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

我们希望有一种计算长度的方法。如果我们想在类中定义它,它将是什么样?

    def length(self):
        return math.sqrt(self.x ** 2 + self.y ** 2)

当我们将其定义为全局方法/函数时,它应该是什么样?

def length_global(vector):
    return math.sqrt(vector.x ** 2 + vector.y ** 2)

因此,整个结构保持不变。我该如何利用呢?如果我们暂时假设没有lengthVector类编写方法,则可以执行以下操作:

Vector.length_new = length_global
v = Vector(3, 4)
print(v.length_new()) # 5.0

之所以有效,是因为的第一个参数length_global可以用作中的self参数length_new。没有明确的说法,这是不可能的self


理解显式需求的另一种方法self是查看Python在何处添加了一些语法糖。当您牢记时,基本上,

v_instance.length()

在内部转换为

Vector.length(v_instance)

很容易看到self适合的位置。您实际上并没有用Python编写实例方法;您编写的是必须将实例作为第一个参数的类方法。因此,您必须将实例参数显式放置在某处。


4
Vector.length_new = length_global ...实际上,我在类声明中开始使用这种语法。每当我只想从另一个类继承某些方法时,只要将引用明确地复制到这些方法即可。
Jeeyoung Kim

2
是否可以说python的“实例方法”只是静态全局方法(如Java或C ++)的语法糖,并且实例对象传入了封装多个属性的实例对象?---好吧,这是半正确的,因为在多态中,“ this”(如在Java中)或“ self”的更重要目的是为您提供方法的正确实现。Python确实有这个。因此,调用myobj.someMethod()等于python中的TheClassOfMyObj.someMethod(myobj)。请注意,“ TheClassOfMyObj”是由python从“ self”中自动找出来的,否则您必须找出来。
泰迪泰迪

3
实际上,如图所示,实例方法不仅是类方法,而且方法仅仅是类的成员的函数Vector.length_new = length_global
2013年

1
“这是可行的,因为可以将length_global的第一个参数重新用作length_new中的self参数。如果没有显式的self,则无法实现。” -它会一样地工作。它会被重新用于隐式self ...第二个示例是循环推理-您必须在其中显式放置self,因为python需要显式self。
Karoly Horvath 2014年

1
@KarolyHorvath:当然,也可以在内部定义的方法不需要显式的self,而外部定义的方法则需要模型的语言。但是我要说的是,在两种情况下都需要显式自我,这是有一定一致性的,这使得这样做是一个合理的理由。其他语言可能会选择不同的方法。
Debilski 2014年

420

假设您有一个ClassA包含methodA定义为以下方法的类:

def methodA(self, arg1, arg2):
    # do something

并且ObjectA是此类的一个实例。

现在,当ObjectA.methodA(arg1, arg2)被调用时,python在内部将其转换为:

ClassA.methodA(ObjectA, arg1, arg2)

self变量是指对象本身。


94
我阅读了所有其他答案,并理解了一些内容,阅读了其中的所有内容,然后才说得通。
赛斯2014年

3
这给我钉了!
Bernard'Beta Berlin'Parah

2
但是,为什么不像Ruby那样保留这些胆量呢?
Cees Timmerman

但是在__init __(self)方法中,它接受self,那么即使不创建对象,它也如何指向自身?
萨拉夫

认真地说,这比Debilski的示例好得多,因为它并不太复杂,人们可能对向量不熟悉。
NoName

215

实例化对象时,对象本身将传递到self参数中。

在此处输入图片说明

因此,对象的数据绑定到该对象。下面是一个示例,您可以如何可视化每个对象的数据外观。注意如何用对象名称替换“自我”。我并不是说下面的示例图是完全准确的,但希望它可以用于可视化自我的使用。

在此处输入图片说明

将对象传递到self参数中,以便对象可以保留其自己的数据。

尽管这可能并不完全准确,但是请考虑如下实例化对象的过程:制作对象时,它将类用作其自己的数据和方法的模板。如果不将其自身的名称传递给self参数,则该类中的属性和方法将保留为常规模板,并且不会引用该对象(属于该对象)。因此,通过将对象的名称传递给self参数,这意味着,如果从一个类实例化100个对象,则它们都可以跟踪自己的数据和方法。

请参见下图:

在此处输入图片说明


嘿,例如,当通过“ bob.name()”访问Bob的属性时,您实际上访问的是bob()。self.name,可以说是从“ init ”开始的吗?
udarH3

3
当在上面的注释中编写bob.name()时,您暗示bob具有一个名为name()的方法,原因是您在名称后添加了括号。但是,在此示例中,没有这种方法。“ bob.name”(不带括号)直接从init(构造方法)方法访问名为name的属性。调用bob的语音方法时,该方法将访问name属性并在print语句中返回它。希望这可以帮助。
sw123456

3
不,您将获得self.name的值,对于bob对象,该值实际上是bob.name,因为对象的名称在创建(实例化)时传递到self参数中。再次希望对您有所帮助。如果有主帖子,请随时对其进行投票。
sw123456

2
名称在实例化时分配给self.name。创建对象后,属于该对象的所有变量都是以“ self”为前缀的变量。请记住,当从类创建对象时,将self替换为对象的名称。
sw123456

5
这就是你解释的东西!干得好:)
penta

80

我喜欢这个例子:

class A: 
    foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: [5]

class A: 
    def __init__(self): 
        self.foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: []

18
所以瓦尔没有自我是类的简单静态瓦尔,就像在Java中
泰迪熊玩具

5
泰迪泰迪,你并不完全正确。行为(静态或非静态)不仅取决于self变量类型,而且取决于变量类型。尝试使用简单的整数而不是list来做第一个示例。结果将完全不同。
康斯坦丁2014年

2
实际上,我对此的疑问是,为什么允许您a.foo在第一个示例中说而不是A.foo?显然foo属于
此类

您可以使用大多数语言从对象实例中调用静态成员。为什么这么惊讶?
Paarth

2
@RadonRosborough因为在第一个示例中,ab都是A()(类)的标签(或指针)。a.foo引用A().foo类方法。在第二个例子,不过,a成为一个参考实例A()一样,b。现在它们是实例,而不是类对象本身,self允许foo方法对实例进行操作。
LegendaryDude

40

我将用不使用类的代码进行演示:

def state_init(state):
    state['field'] = 'init'

def state_add(state, x):
    state['field'] += x

def state_mult(state, x):
    state['field'] *= x

def state_getField(state):
    return state['field']

myself = {}
state_init(myself)
state_add(myself, 'added')
state_mult(myself, 2)

print( state_getField(myself) )
#--> 'initaddedinitadded'

类只是避免始终传递此“状态”事物的一种方法(以及其他诸如初始化,类组合,很少需要的元类以及支持自定义方法以覆盖运算符之类的美好事物)的方法。

现在,让我们使用内置的python类机制来演示上面的代码,以显示其基本相同之处。

class State(object):
    def __init__(self):
        self.field = 'init'
    def add(self, x):
        self.field += x
    def mult(self, x):
        self.field *= x

s = State()
s.add('added')    # self is implicitly passed in
s.mult(2)         # self is implicitly passed in
print( s.field )

[从重复的封闭式问题中迁移了我的答案]


1
我希望Python能够像Ruby一样处理处理程序。
Cees Timmerman

20

以下摘录来自Python文档中关于self的内容

与Modula-3中一样,[Python]中没有用于从其方法引用该对象的成员的简写:方法函数以表示该对象的显式第一个参数声明,该参数由调用隐式提供。

通常,方法的第一个参数称为self。这无非是一种约定:self对Python绝对没有特殊的含义。但是请注意,如果不遵循该约定,则其他Python程序员可能对代码的可读性较低,并且还可以想到可能会依赖此类约定编写类浏览器程序。

有关更多信息,请参见关于类Python文档教程


20

除已说明的所有其他原因外,它还允许更轻松地访问重写的方法;你可以打电话Class.some_method(inst)

一个有用的例子:

class C1(object):
    def __init__(self):
         print "C1 init"

class C2(C1):
    def __init__(self): #overrides C1.__init__
        print "C2 init"
        C1.__init__(self) #but we still want C1 to init the class too
>>> C2()
"C2 init"
"C1 init"


16

与Java或C ++不同,Python不是为面向对象编程而构建的语言。

在Python中调用静态方法时,只需编写一个内部带有常规参数的方法。

class Animal():
    def staticMethod():
        print "This is a static method"

但是,对象方法需要您创建一个变量,在这种情况下,该方法是动物,需要使用self参数

class Animal():
    def objectMethod(self):
        print "This is an object method which needs an instance of a class"

self方法还用于引用类中的变量字段。

class Animal():
    #animalName made in constructor
    def Animal(self):
        self.animalName = "";


    def getAnimalName(self):
        return self.animalName

在这种情况下,self指的是整个类的animalName变量。记住:如果方法中有变量,则self将不起作用。该变量仅在该方法运行时才存在。为了定义字段(整个类的变量),您必须在类方法之外定义它们。

如果您听不懂我在说什么,请使用Google“面向对象编程”。一旦理解了这一点,您甚至不需要问这个问题:)。


1,因为之间的区别staticMethod()objectMethod(self)。我想补充一点,为了调用第一个,您会说Animal.staticMethod(),同时objectMethod()需要一个实例:a = Animal(); a.objectMethod()
Laryx Decidua 2015年

您所说的不是100%正确。那只是一个约定。您仍然可以从创建的对象调用静态方法。您只是不能使用任何类成员,因为您没有声明自己。我什至可以调用Animal.objectMethod(animalObj)来调用非静态对象。基本上,这意味着静态方法只是不使用成员变量的方法。不需要声明自己。我认为这是一种愚蠢的语言要求。诸如Lua和C ++之类的语言为您提供了幕后的obj变量。
user441521 '01

您做了一个无用的animalName字符串声明,并导致了animalName方法崩溃。
Cees Timmerman

3
@ytpillai不相关。令人困惑和错误的代码不应作为答案。
Cees Timmerman

1
def getAnimalName不要破坏您要返回的字符串,并self引用该类的实例,而不是其中的任何字段。
Cees Timmerman

10

可以遵循Python禅宗的“显式优于隐式”的说法。它确实是对您的类对象的引用。例如,在Java和PHP中,它称为this

如果user_type_name模型上的字段为,则可以通过进行访问self.user_type_name


10

首先,自我是一个常规名称,您可以代之以其他任何东西(连贯一致)。

它指的是对象本身,因此,在使用它时,您声明.name和.age是要创建的Student对象的属性(注意,不是Student类的属性)。

class Student:
    #called each time you create a new Student instance
    def __init__(self,name,age): #special method to initialize
        self.name=name
        self.age=age

    def __str__(self): #special method called for example when you use print
        return "Student %s is %s years old" %(self.name,self.age)

    def call(self, msg): #silly example for custom method
        return ("Hey, %s! "+msg) %self.name

#initializing two instances of the student class
bob=Student("Bob",20)
alice=Student("Alice",19)

#using them
print bob.name
print bob.age
print alice #this one only works if you define the __str__ method
print alice.call("Come here!") #notice you don't put a value for self

#you can modify attributes, like when alice ages
alice.age=20
print alice

代码在这里


1
您的回答对我来说似乎是最清晰的。+1
Pawel

9

self是对对象本身的对象引用,因此它们是相同的。在对象本身的上下文中未调用Python方法。 self在Python中,可能用于处理自定义对象模型之类的东西。


8

使用通常称为参数的参数self并不难理解,为什么要这样做呢?还是关于为什么要明确提及?我想,对于大多数查询此问题的用户来说,这是一个更大的问题,或者如果不是,则在继续学习python时,他们肯定会遇到相同的问题。我建议他们阅读以下两个博客:

1:自我解释

请注意,它不是关键字。

每个类方法(包括init)的第一个参数始终是对当前类实例的引用。按照惯例,此参数始终命名为self。在init方法中,self指的是新创建的对象;在其他类方法中,它引用其方法被调用的实例。例如,下面的代码与上面的代码相同。

2:为什么要用这种方式,为什么不能像Java那样将其作为参数消除,而要用关键字代替

我想补充的另一件事是,可选self参数允许我通过不编写而在类内声明静态方法self

代码示例:

class MyClass():
    def staticMethod():
        print "This is a static method"

    def objectMethod(self):
        print "This is an object method which needs an instance of a class, and that is what self refers to"

聚苯乙烯:仅在Python 3.x中有效。

在以前的版本中,必须显式添加@staticmethod装饰器,否则self必须使用参数。


7

我很惊讶没有人提出Lua。Lua也使用'self'变量,但是可以省略但仍然使用。C ++对“ this”的作用相同。我没有看到任何理由必须在每个函数中声明“ self”,但是您仍然应该能够像在lua和C ++中一样使用它。对于一种以简短为荣的语言,奇怪的是它要求您声明自变量。


6

请看以下示例,该示例清楚地说明了 self

class Restaurant(object):  
    bankrupt = False

    def open_branch(self):
        if not self.bankrupt:
           print("branch opened")

#create instance1
>>> x = Restaurant()
>>> x.bankrupt
False

#create instance2
>>> y = Restaurant()
>>> y.bankrupt = True   
>>> y.bankrupt
True

>>> x.bankrupt
False  

self 用于/需要区分实例。

资料来源:python中的self变量解释-Pythontips


是的,我想我们知道为什么要使用自我,但问题是为什么该语言使您明确声明了自我。许多其他语言都不需要这样做,而以它的简短而引以为傲的语言,您可能会认为它们只会为您提供像Lua或C ++这样的在幕后使用的变量。
user441521 '01

3
@ kmario23您的答复是从这里发送的:pythontips.com/2013/08/07/the-self-variable-in-python-explained 请在发布答案时以自己的名义确认原始作者。
geekidharsh

@geekidharsh谢谢,我加了一条纸条!
kmario23

5

是因为按照python的设计方式,替代方法几乎行不通。Python旨在允许在无法使用隐式this(a-la Java / C ++)或显式@(a-la ruby​​)的上下文中定义方法或函数。我们来看一个使用python约定的显式方法的示例:

def fubar(x):
    self.x = x

class C:
    frob = fubar

现在,该fubar功能将无法使用,因为它将假定它self是一个全局变量(以及in frob)。另一种方法是执行具有替换后的全局范围的方法(其中self对象)。

隐式方法是

def fubar(x)
    myX = x

class C:
    frob = fubar

这意味着myX它将被解释为fubarfrob以及)中的局部变量。这里的替代方法是执行具有替换的局部作用域的方法,该局部作用域在调用之间保留,但是这将消除方法局部变量的可能性。

但是,目前的情况很好:

 def fubar(self, x)
     self.x = x

 class C:
     frob = fubar

这里的时候,被称为一方法frob将接收上它通过调用对象self的参数,并且fubar仍然可以用一个对象作为参数调用和工作一样(这一样的C.frob,我认为)。


3

在该__init__方法中,self指的是新创建的对象;在其他类方法中,它引用其方法被调用的实例。

自我,正如名字一样,只是一个约定,可以随意称呼它!但是在使用它(例如删除对象)时,必须使用相同的名称:__del__(var),其中var在使用__init__(var,[...])

您也应该看一下cls,以了解更大的情况。这篇文章可能会有所帮助。


3

self的作用类似于当前的对象名称或class的实例。

# Self explanation.


 class classname(object):

    def __init__(self,name):

        self.name=name
        # Self is acting as a replacement of object name.
        #self.name=object1.name

   def display(self):
      print("Name of the person is :",self.name)
      print("object name:",object1.name)


 object1=classname("Bucky")
 object2=classname("ford")

 object1.display()
 object2.display()

###### Output 
Name of the person is : Bucky
object name: Bucky
Name of the person is : ford
object name: Bucky

1

self 是不可避免的。

只是有一个问题应该self是隐性或显性的。 Guido van Rossum解决了这个问题,说self必须留下

那么self住在哪里?

如果我们只是坚持使用函数式编程,那就不需要了self。进入Python OOP之后,我们发现self其中。

这是class C该方法的典型用例m1

class C:
    def m1(self, arg):
        print(self, ' inside')
        pass

ci =C()
print(ci, ' outside')
ci.m1(None)
print(hex(id(ci))) # hex memory address

该程序将输出:

<__main__.C object at 0x000002B9D79C6CC0>  outside
<__main__.C object at 0x000002B9D79C6CC0>  inside
0x2b9d79c6cc0

因此self保留了类实例的内存地址。 的目的self实例方法保留引用,并让我们可以显式访问该引用。


请注意,有三种不同类型的类方法:

  • 静态方法(阅读:函数),
  • 类方法
  • 实例方法(提到)。

0

文档

方法的特殊之处在于,实例对象作为函数的第一个参数传递。在我们的示例中,该调用x.f()与完全等效MyClass.f(x)。通常,调用带有n个参数列表的方法等同于调用带有参数列表的函数,该参数列表是通过在第一个参数之前插入方法的实例对象而创建的。

在相关片段之前,

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

x = MyClass()


-2

它是对类实例对象的显式引用。


21
我认为这不会帮助richzilla了解其背后的原因。
GeorgSchölly10年

1
@SilentGhost:您已将其钉牢。我很佩服。如果我正确理解:我确实将对象创建为已定义类的实例,而self参数引用该对象吗?我了解自我以隐式方式指向班级本身,但是如果您再解释一下答案会很棒。
dkrynicki
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.