Python中self字的目的是什么?我理解它指的是由该类创建的特定对象,但我不明白为什么需要显式地将它作为参数添加到每个函数中。为了说明这一点,在Ruby中我可以这样做:
1 2 3 4 5
| class myClass
def myFunc(name)
@name = name
end
end |
我很容易理解。但是在Python中,我需要包含self:
1 2 3
| class myClass:
def myFunc(self, name):
self.name = name |
有人能跟我说说吗?在我有限的经验中,我从未遇到过这种情况。
- 你可能会对Guido van Rossum的这篇文章"为什么外显自我必须留下来"很感兴趣:neopythonic.blogspot.com/2008/10/…
- 参见"为什么必须在方法定义和调用中显式使用self":docs.python.org/faq/…
- "这我很容易理解"——相当主观,你不这么认为吗?是什么使得@name比self.name更直观?在我看来,后者更直观。
- 虽然玩魔鬼游戏提倡很容易忘记添加额外的参数到每个方法,并有奇怪的行为,当你忘记,这使初学者很难。我宁愿对不寻常的东西(如静态方法)进行详细说明,也不愿对正常的行为(如实例方法)进行详细说明。
- @santa,我没有得到@name和self.name,这就是为什么每个函数都需要一个额外的参数。现在问题解决了。
- 除了Ruby比较,这与[如何避免显式的"self"?(由于这种差异,我不会以一个被愚弄的人来结尾,但任何对此感兴趣的人都应该阅读这两组答案。)
- @Piotr—我假设您禁用了垃圾收集器?显式地管理内存比让一些垃圾收集器一直隐式地释放内存要好。
- 这就是函数和类方法之间的关键区别。函数是自由浮动的,不受约束的。类(实例)方法必须知道它的父类(和父属性),因此需要将方法的引用传递给父类(作为self)。在理解OOP之前,您必须将它内部化,这是一个不那么隐式的规则。其他语言选择语法糖而不是语义简单性,python不是其他语言。
- @CatPlusPlus"显式优于隐式"是Python禅宗中的第二条规则;规则1是"美丽总比丑陋好",它主张忽略自我。
- @I.J。肯尼迪:不完全是。Sigils或隐式作用域要难看得多。无论如何,在存在类属性且没有静态验证的情况下,没有标记的隐含并不会起作用。
- 嗯,你从来没有‘及格’过,self。您可以像getUserType()那样调用该方法。如果您需要另一个参数,是的,您将需要定义方法来获取另一个参数。
- 恶心,自我。为什么编译器不直接处理它并将self作为关键字呢?这并不坏,因为它已经在许多编程语言中作为"this"或类似的名称出现。根据我的经验,太多的东西对你是有害的。太多的糖,太多的水,太多的明确的电话。显式只有在显式更方便时才显式地使用>。如果我们要让self显式,为什么不让整个语言显式,让用户自己编写和编译呢?
- 如果显式调用优于隐式调用,那么所有方法调用都应该采用MyClass.memberMethod(instanceOfMyClass,arg1,arg2)的形式。调用应该显式地提供对象。
- 我不认为"显式优于隐式"能够很好地解释这种设计选择。@foo和self.foo同样是显式的,因为不需要进行隐式解析(例如,在c++中,可以"隐式"访问实例成员,而不需要使用名称空间进行"显式"访问)。惟一的区别是Ruby引入了一个新的语义(@),而Python没有。一个新的语义是否值得避免过多的冗长纯粹是主观的。不过,应该注意的是,大多数现代语言都选择在这里引入一个概念(例如php的$this, JS的this)。
- 它可能被推得很短,但是已经有人开玩笑说"你传递黄油"了吗?
需要使用self.的原因是Python不使用@语法来引用实例属性。Python决定采用一种方法,使方法所属的实例自动传递,而不是自动接收:方法的第一个参数是方法所调用的实例。这使得方法与函数完全相同,并将实际的名称留给您自己使用(尽管self是惯例,当您使用其他东西时,人们通常会对您皱眉头)。
Python本可以做一些其他的事情来区分普通名称和属性——像Ruby那样的特殊语法,或者需要像c++和Java那样的声明,或者做一些更不同的事情——但是它没有这样做。Python的全部功能是使事情显式化,使什么是什么一目了然,尽管它并不是在所有地方都这样做,但它确实在实例属性上这样做。这就是为什么赋值给实例属性需要知道赋值给哪个实例,这就是为什么它需要self.。
- 除了使用cls而不是self之外,还有一个例外,例如在使用@classmethod装饰器时。
- @Georg: cls指的是类对象,而不是实例对象
- 例外情况是,它不是一个"常规"方法或"实例方法",而是其他东西——类方法、静态方法或普通函数:)
- @SilentGhost:实际上,第一个参数的名称是您想要的任何名称。对于类方法,惯例是使用cls,对于实例方法,惯例是使用self。如果需要,可以对类方法使用self,对实例方法使用cls。如果我喜欢,我还可以使用bob和fnord。
- 我发现有趣的是,社区没有选择this而选择了self。self是否有一些我在旧的编程语言中不知道的历史?
- @Julius The self来自模块化-3的约定,关于这个选择的更多细节,请参见这个答案。(免责声明:我)。
- @ThomasWouters—python中的"self"关键字与Java中的"this"关键字完全相同,这样说对吗?如果没有,有什么区别?
- @Julius的self关键字(Smalltalk, 1980)早于this关键字(来自c++)。看到:stackoverflow.com/questions/1079983/…
- 如果self能够像Lua和c++ (this)那样在幕后提供给我们,那就太好了。"Python的全部功能就是让事情变得显式,让什么是什么变得显而易见,尽管它并不是在所有地方都这么做,但它确实会在实例属性上这么做。"你这样结束是件好事,因为我来自其他语言,我正要讨论第一部分。使用空白来表示意思根本不是一件显式的事情,它是python的核心。我认为与其他语言相比,Python一点也不显式。为什么不再显式声明self是一个问题。
- 通常,方法的第一个参数被称为self。这只不过是一个约定:self这个名称对Python绝对没有特殊的含义。
- 我认为这个语句应该加粗:方法的第一个参数是方法被调用的实例。
- Python实例方法看起来像c#扩展方法,其中第一个参数引用实例,不管为它选择什么名称。在我看来,这是丑陋的和不必要的,但如果我想要一个适合我所有的喜好的语言,我可能应该做我自己的编程语言。
- 只有当方法调用如下:o = myClass();myFunc (o,"名字");
- 这个答案在显式self的_true_reasons中缺少一个非常重要的部分,正如这里的wiki.python.org/moin/FromFunctionToMethod所解释的那样,显式self是python"方法"实际上只是普通的函数,因此语言需要一种方法将当前实例传递给函数。
我们来看一个简单的向量类:
1 2 3 4
| class Vector:
def __init__(self, x, y):
self.x = x
self.y = y |
我们想要一个计算长度的方法。如果我们想在类中定义它会是什么样子?
1 2
| def length(self):
return math.sqrt(self.x ** 2 + self.y ** 2) |
当我们将它定义为一个全局方法/函数时,它应该是什么样的呢?
1 2
| def length_global(vector):
return math.sqrt(vector.x ** 2 + vector.y ** 2) |
所以整个结构保持不变。我怎么才能利用这个呢?如果我们假设我们没有为我们的Vector类编写一个length方法,我们可以这样做:
1 2 3
| Vector.length_new = length_global
v = Vector(3, 4)
print(v.length_new()) # 5.0 |
这是因为length_global的第一个参数可以作为length_new中的self参数重用。如果没有显式的self,这是不可能的。
理解显式self的需要的另一种方法是查看Python在哪里添加了一些语法糖。当你记在心里的时候,那基本上就是一个电话
内部转化为
1
| Vector.length(v_instance) |
很容易看出self的位置。你不用Python写实例方法;您所编写的是类方法,它必须以实例作为第一个参数。因此,您必须显式地将实例参数放在某个位置。
- 向量。length_new = length_global……实际上,我开始在类声明中使用这样的语法。每当我只想从另一个类继承一些方法时,我只是显式地将引用复制到这些方法。
- python的"实例方法"仅仅是静态全局方法(如在Java或c++中)的语法糖,传递一个实例对象来封装多个属性,这样说公平吗?——这有一半是对的,因为在多态性中,"this"(在java中)或"self"更重要的目的是为您提供正确的方法实现。Python确实有。调用myobj。somemethod()等于python中的theclassofmyobj。somemethod (myobj)注意,"TheClassOfMyObj"是由python从"self"自动计算出来的,否则您必须找出它。
- 事实上,不仅实例方法只是类方法,而且方法只是类成员的函数,如Vector.length_new = length_global所示。
- 这是可行的,因为length_global的第一个参数可以被重用为length_new中的self参数。没有明确的自我,这是不可能的。"-它的工作原理是一样的。它会被内隐的自我重复使用……第二个例子是循环推理——您必须显式地将self放在那里,因为python需要显式的self。
- @KarolyHorvath:当然,也有可能有这样一种语言,它的模型中,内部定义的方法不需要显式的self,而外部定义的方法需要。但我想说的是,在这两种情况下都需要显式自我,这是一个合理的理由。其他语言可能会选择不同的方法。
- 那么,使用Ruby,函数和方法之间的重构是否需要搜索每个@variables并删除@符号?(伟大的回答,谢谢!)
- 我认为,甚至在技术上,v_instance.length()被转化为Vector.length.__get__(v_instance, Vector)(),但这可能使水比我们想要的更泥泞;-)
- 或者甚至像type(v_instance)而不是之前的Vector。
- 作为继ruby之后学习python的人,最后一段对self的区别做了很大的总结
- "你实际上不用Python编写实例方法;您所编写的是类方法,它(必须)以实例作为第一个参数。因此,您必须显式地将实例参数放在某个位置。"这比上面的文字解释得更清楚。
- 最后一段很好。这应该是最重要的答案。
假设您有一个类ClassA,其中包含一个方法methodA,定义为:
1 2
| def methodA(self, arg1, arg2):
# do something |
ObjectA是这个类的一个实例。
现在当调用ObjectA.methodA(arg1, arg2)时,python内部将它转换为:
1
| ClassA.methodA(ObjectA, arg1, arg2) |
self变量引用对象本身。
- 我读了所有其他的答案,有点明白了,我读了这一个,然后一切都有了意义。
- 这被称为magic answer _magic__()
- 这已经在德布斯基的后半部分的答案。
- 这对我来说太棒了!
- 不过,为什么不像Ruby那样,保留这些核心内容呢?
- 这应该就是答案!!中肯而精确
- 但是在_init__(self)方法中,它接受self,即使不创建对象,它如何引用自己?
当对象被实例化时,对象本身被传递给self参数。
因此,对象的数据被绑定到对象。下面是一个示例,演示如何可视化每个对象的数据。注意self是如何被对象名称替换的。我并不是说下面的这个例子图是完全准确的,但希望它能对可视化self的使用有帮助。
对象被传递到self参数中,以便对象可以保存自己的数据。
虽然这可能不是完全准确的,但是可以这样考虑实例化一个对象的过程:当一个对象被创建时,它将该类用作它自己的数据和方法的模板。如果不将它自己的名称传递给self参数,类中的属性和方法将保留为通用模板,并且不会引用(属于)对象。因此,通过将对象的名称传递给self参数,这意味着如果从一个类实例化100个对象,它们都可以跟踪自己的数据和方法。
见下图:
- 嘿,当访问Bob的属性时,例如通过" Bob .name()",实际上是从init访问bob().self.name,对吧?
- 当您在上面的注释中编写bob.name()时,您是在暗示bob有一个名为name()的方法,因为您在name后面添加了括号。但是在这个例子中没有这样的方法。name(没有括号)直接从init(构造函数)方法访问名为name的属性。当调用bob的speak方法时,它是访问name属性并在print语句中返回该属性的方法。希望这个有帮助。
- 是的,没有了副题,我想写sry。你得到的是name的值而不是self。name因为据我所知self。name和name是两个不同的变量。谢谢
- 不,您获得self.name的值,对于bob对象,它实际上是bob.name,因为对象的名称在创建(实例化)时传递给self参数。希望这能有所帮助。如果主页有的话,请随意投票。
- Name在实例化时被分配给self.name。创建对象之后,属于该对象的所有变量都是前缀为"self"的变量。记住,self在从类创建时被对象的名称替换。
- 非常清楚的解释。但是,如何验证它的正确性呢?
- 这就是你解释事情的方式!不错:)
我喜欢这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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: [] |
- 所以没有self的vars只是类的静态vars,就像在java中一样
- 泰迪,泰迪,你不完全正确。行为(静态或非静态like)不仅取决于self,还取决于变量类型。尝试用简单整数而不是list来做第一个例子。结果将大不相同。
- 实际上,我的问题是,为什么允许在第一个示例中使用a.foo而不是A.foo?显然foo属于类…
- 您可以在大多数语言中从对象的实例中调用静态成员。为什么会令人惊讶呢?
- @RadonRosborough,因为在第一个例子中,a和b都是A()(类)的标签(或指针)。a.foo引用A().foo类方法。但是,在第二个示例中,a和b一样成为对A()实例的引用。既然它们是实例而不是类对象本身,self允许foo方法对实例进行操作。
我将用不使用类的代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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类机制来演示上面的代码,以展示它们是如何基本相同的。
1 2 3 4 5 6 7 8 9 10 11 12
| 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 ) |
[把我的答案从重复的封闭式问题中移走]
- 我希望Python能够像Ruby那样为处理程序添加糖衣炮弹。
以下摘录自Python关于self的文档:
As in Modula-3, there are no shorthands [in Python] for referencing the object’s members from its methods: the method function is declared with an explicit first argument representing the object, which is provided implicitly by the call.
Often, the first argument of a method is called self. This is nothing more than a convention: the name self has absolutely no special meaning to Python. Note, however, that by not following the convention your code may be less readable to other Python programmers, and it is also conceivable that a class browser program might be written that relies upon such a convention.
有关更多信息,请参阅有关类的Python文档教程。
和前面提到的所有其他原因一样,它允许更容易地访问被覆盖的方法;您可以调用Class.some_method(inst)。
举个有用的例子:
1 2 3 4 5 6 7 8
| 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 |
1 2 3
| >>> C2()
"C2 init"
"C1 init" |
它的使用类似于在Java中使用this关键字,即给当前对象一个引用。
- 类myClass: def myFunc(this, name): this.name = name
与Java或c++不同,Python不是为面向对象编程而构建的语言。
在Python中调用静态方法时,只需编写一个包含常规参数的方法。
1 2 3
| class Animal():
def staticMethod():
print"This is a static method" |
然而,object方法需要创建一个变量(在本例中是动物),它需要self参数
1 2 3
| class Animal():
def objectMethod(self):
print"This is an object method which needs an instance of a class" |
self方法还用于引用类中的变量字段。
1 2 3 4 5 6 7 8
| class Animal():
#animalName made in constructor
def Animal(self):
self.animalName ="";
def getAnimalName(self):
return self.animalName |
在本例中,self引用了整个类的animalName变量。记住:如果方法中有一个变量,self将不起作用。该变量仅在方法运行时存在。要定义字段(整个类的变量),必须在类方法之外定义它们。
如果你不明白我说的任何一个字,那么谷歌"面向对象编程"。一旦你理解了这一点,你甚至不需要问这个问题:)。
- +1因为staticMethod()和objectMethod(self)之间的区别。我想补充一点,为了调用第一个,您可以说Animal.staticMethod(),而objectMethod()需要一个实例:a = Animal(); a.objectMethod()
- 你说的不是百分之百正确。这只是一个惯例。您仍然可以从创建的对象中调用静态方法。您不能使用任何类成员,因为您没有声明self。我甚至可以调用Animal.objectMethod(animalObj)来调用非静态方法。基本上,这意味着静态方法只是不使用成员变量的方法。没有必要声明self。我认为这是一个愚蠢的语言要求。像Lua和c++这样的语言在幕后为您提供了obj变量。
- 唯一有意义的答案!谢谢你! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
- 您创建了一个无用的animalName字符串声明并破坏了animalName方法。
- 对于@user441521, python的目的是编写脚本而不是oop,它在oop标准中并不出色。对蒂默曼来说,这篇文章是为了教育目的而写的,这是一个小错误,只有那些没有理解就简单地复制粘贴的人,才会发现这是不道德的,会对答案有问题。
- @ytpillai无关紧要。混淆和不正确的代码不应该作为一个答案。
- 固定的问题
- self引用类的实例,而不是类内部的任何字段。
- 要定义字段(整个类的变量),您必须在类方法之外定义它们。类属性和实例属性之间的区别是非常模糊的——你可以在实例方法中创建实例属性——如果你在它们前面加上类名,创建类属性也可以工作……Animal.ClawDamage = 200内部的def getAnimalName(self):工作得很好-任何动物都会有这个属性
它遵循Python的禅"显式优于隐式"。它确实是对类对象的引用。例如,在Java和PHP中,它被称为this。
如果user_type_name是模型上的字段,则由self.user_type_name访问它。
self是对象本身的对象引用,因此它们是相同的。Python方法不会在对象本身的上下文中调用。self在Python中可以用来处理自定义对象模型或其他东西。
首先,self是一个传统的名字,你可以用其他任何东西来代替它。
它引用对象本身,所以当您使用它时,您声明.name和.age是要创建的学生对象的属性(注意,不是学生类的属性)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 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 |
代码在这里
我很惊讶没有人提到Lua。Lua还使用"self"变量,不过可以省略它,但仍然使用它。c++对"this"也做了同样的处理。我不认为有任何理由必须在每个函数中声明'self',但您应该仍然能够像使用lua和c++一样使用它。对于一种以简洁而自豪的语言来说,它要求声明self变量是很奇怪的。
这个参数的使用,传统上称为self并不难理解,但是为什么它是必要的呢?或者为什么要明确提到它?我想,对于大多数查询这个问题的用户来说,这是一个更大的问题,如果不是,那么当他们继续学习python时,肯定会遇到同样的问题。我建议他们阅读以下几个博客:
1:使用自我解释
注意,它不是一个关键字。
The first argument of every class method, including init, is always a reference to the current instance of the class. By convention, this argument is always named self. In the init method, self refers to the newly created object; in other class methods, it refers to the instance whose method was called. For example the below code is the same as the above code.
第2集:为什么我们要这样做,为什么我们不能像Java那样把它作为一个参数删除,而用一个关键字来代替
我想添加的另一件事是,一个可选的self参数允许我在类中声明静态方法,而不需要编写self。
代码示例:
1 2 3 4 5 6
| 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" |
PS:这只适用于Python 3.x。
在以前的版本中,必须显式地添加@staticmethod装饰器,否则必须使用self参数。
请看下面的示例,它清楚地解释了self的目的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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用于/需要区分实例。
- 是的,我认为我们知道为什么使用self,但问题是为什么语言会让你显式地声明它。许多其他语言不需要这样做,而一种以简洁而自豪的语言,您可能会认为它们只是在幕后为您提供了像Lua或c++ (this)那样使用的变量。
- @kmario23你的回复来自这里:pythontips.com/2013/08/07/the self- variin python- explai&zw203;
因为按照python的设计方式,这些替代方案很难奏效。Python旨在允许在隐式this (a-la Java/ c++)或显式@ (a-la ruby)都不能工作的上下文中定义方法或函数。让我们举一个python约定显式方法的例子:
1 2 3 4 5
| def fubar(x):
self.x = x
class C:
frob = fubar |
现在fubar函数无法工作,因为它假定self是一个全局变量(在frob中也是)。另一种方法是使用替换的全局范围(其中self是对象)执行方法。
隐式方法是
1 2 3 4 5
| def fubar(x)
myX = x
class C:
frob = fubar |
这将意味着myX将被解释为fubar(以及frob中的一个局部变量)。这里的另一种选择是使用替换的局部作用域来执行方法,该局部作用域在调用之间保留,但是这将删除方法局部变量的可能性。
然而,目前的情况很好:
1 2 3 4 5
| def fubar(self, x)
self.x = x
class C:
frob = fubar |
在这里,当frob作为方法调用时,它将接收通过self参数调用它的对象,并且fubar仍然可以使用对象作为参数调用,并且工作方式相同(我认为它与C.frob相同)。
在__init__方法中,self引用新创建的对象;在其他类方法中,它引用其方法被调用的实例。
self,作为一个名字,只是一个约定,你想怎么叫就怎么叫!但是,当使用它时,例如删除对象时,您必须使用相同的名称:__del__(var),其中var在__init__(var,[...])中使用。
您也应该查看一下cls,以获得更全面的信息。这篇文章可能会有帮助。
它是对类实例对象的显式引用。
- 我不认为这能帮助瑞奇拉了解其背后的原因。
- 你说对了。我的印象。如果我理解正确:我确实创建了一个对象作为已定义类的实例,并且self参数引用了该对象?我知道self指的是类本身但如果你能多解释一下你的答案就好了。