向初学者解释python'self'变量

时间:2011-08-09 00:18:45

标签: python oop class scope

我几乎不知道OOP术语和概念。我从概念上知道对象是什么,对象有方法。我甚至明白在python中,类是对象!那很酷,我只是不知道它意味着什么。它没有点击我。

我目前正在尝试理解一些我认为将阐明我对python的理解的详细答案:

  1. What does the "yield" keyword do in Python?
  2. What is a metaclass in Python?
  3. 在第一个答案中,作者使用以下代码作为示例:

    >>> class Bank(): # let's create a bank, building ATMs
    ...    crisis = False
    ...    def create_atm(self) :
    ...        while not self.crisis :
    ...            yield "$100"
    

    我没有立即了解self指向的内容。这绝对是不理解类的一个症状,我将在某些时候开展工作。澄清一下,

    >>> def func():
    ...   for i in range(3):
    ...     print i
    

    我理解i指向列表range(3)中的一个项目,因为它在函数中,不是全局的。但是self“指向什么?”

8 个答案:

答案 0 :(得分:92)

我会首先尝试清除一些关于类和对象的混淆。让我们看看这段代码:

>>> class Bank(): # let's create a bank, building ATMs
...    crisis = False
...    def create_atm(self) :
...        while not self.crisis :
...            yield "$100"

评论有点具欺骗性。上面的代码没有“创建”银行。它定义了银行是什么。银行是具有名为crisis的属性和函数create_atm的东西。这就是上面代码所说的内容。

现在让我们创建一个银行:

>>> x = Bank()

在那里,x现在是一家银行。 x有一个属性crisis和一个函数create_atm。在python中调用x.create_atm();与调用Bank.create_atm(x);相同,所以现在self引用x。如果您添加另一家名为y的银行,则调用y.create_atm()会知道y的危机值,而不是x,因为在该函数中self }指y

self只是一个命名约定,但坚持下去是非常好的。值得指出的是,上面的代码相当于:

>>> class Bank(): # let's create a bank, building ATMs
...    crisis = False
...    def create_atm(thisbank) :
...        while not thisbank.crisis :
...            yield "$100"

答案 1 :(得分:18)

可能会帮助您将obj.method(arg1, arg2)调用语法视为调用method(obj, arg1, arg2)的纯语法糖(除了method通过obj类型查找,并不是全球性的。

如果以这种方式查看,obj是函数的第一个参数,传统上在参数列表中将其命名为self。 (实际上,您可以将其命名为其他内容,并且您的代码将正常运行,但其他Python编码器会对您不满。)

答案 2 :(得分:12)

self ”是实例对象在调用时自动传递给类实例的方法,以识别调用它的实例。 “ self ”用于从方法内部访问对象的其他属性或方法。 (方法基本上只是属于一个类的函数)

当您已有可用实例时,在调用方法时不需要使用

self ”。

从方法内部访问“some_attribute”属性:

class MyClass(object):
    some_attribute = "hello"

    def some_method(self, some_string):
        print self.some_attribute + " " + some_string

从现有实例访问“some_attribute”属性:

>>> # create the instance
>>> inst = MyClass()
>>>
>>> # accessing the attribute
>>> inst.some_attribute
"hello"
>>> 
>>> # calling the instance's method
>>> inst.some_method("world") # In addition to "world", inst is *automatically* passed here as the first argument to "some_method".
hello world
>>> 

这是一个小代码,用于演示self与实例相同:

>>> class MyClass(object):
>>>     def whoami(self, inst):
>>>         print self is inst
>>>
>>> local_instance = MyClass()

>>> local_instance.whoami(local_instance)
True

正如其他人所提到的,它按照惯例命名为“ self ”,但它可以命名为任何东西。

答案 3 :(得分:5)

self指的是Bank的当前实例。当您创建新的Bank并在其上调用create_atm时,self将由python隐式传递,并将引用您创建的银行。

答案 4 :(得分:5)

  

我没有立即了解self指向的内容。这绝对是不理解课程的一种症状,我将在某些时候继续学习。

self是传递给函数的参数。在Python中,第一个参数隐含地是调用该方法的对象。换句话说:

class Bar(object):
    def someMethod(self):
        return self.field

bar = Bar()

bar.someMethod()
Bar.someMethod(bar)

最后两行具有相同的行为。 (除非bar引用Bar的子类的对象 - 然后someMethod()可能引用不同的函数对象。)

请注意,您可以将“特殊”第一个参数命名为您想要的任何内容 - self只是方法的约定。

  

我理解i指向列表range(3)中的一个项目,因为它在函数中,不是全局的。但是self“指向什么?”

该函数的上下文中不存在名称self。试图使用它会引发NameError


示例脚本:

>>> class Bar(object):
...     def someMethod(self):
...         return self.field
...
>>> bar = Bar()
>>> bar.field = "foo"
>>> bar.someMethod()
'foo'
>>> Bar.someMethod(bar)
'foo'
>>> def fn(i):
...     return self
...
>>> fn(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fn
NameError: global name 'self' is not defined

答案 5 :(得分:2)

“self”的原因(根据惯例)是当Python运行时看到Object.Method(Param1,Param2)形式的调用时,它调用带参数的Method(Object,Param1,Param2)。因此,如果你将第一个参数称为“自我”,那么每个人都会知道你在说什么。

你必须这样做的原因是另一个问题的主题。

就元类而言,这是很少使用的东西。你可能想看看: http://python-history.blogspot.com/2009/04/metaclasses-and-extension-classes-aka.html,原始作者和当前仁慈的Python生活独裁者解释了这是什么,以及它是如何形成的。他还有一篇关于一些可能用途的好文章,但大多数人根本不会直接使用它。

答案 6 :(得分:2)

一个Rubyist的观点(Ruby是我的第一个编程语言,所以我为我即将使用的过于简单,可能错误的抽象道歉)

据我所知,点运算符,例如:

os.path

os被传递到path()作为其第一个变量“无形”

好像os.path就是这样:

path(os)

如果有菊花链,我会想到这个:

os.path.filename

在现实中会有点像这样*:

filename(path(os))

这是令人反感的部分 因此,使用自变量所做的一切就是允许CLASS METHOD(从rubyist的角度来看python'实例方法'似乎是类方法......)通过将一个实例作为第一个变量传递给它来充当实例方法(通过上面的“偷偷摸摸”点方法)按惯例称为self。我自己不是一个实例

c = ClassName()
c.methodname

但班级本身:

ClassName.methodname

该类将被传入而不是实例。

好的,记住的重要一点是__init__方法被某些人称为“魔法”。所以不要担心传递什么来生成新实例。说实话,它可能是nil

答案 7 :(得分:1)

self指的是该类的实例。