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

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

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

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

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

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

答案

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

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

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

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)

因此,整个结构保持不变。我该如何利用呢?如果暂时假设我们没有为Vector类编写length方法,则可以这样做:

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

之所以length_global ,是因为可以将length_global的第一个参数重新用作length_newself参数。没有明确的self这是不可能的。


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

v_instance.length()

在内部转换为

Vector.length(v_instance)

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

假设您有一个ClassA类,其中包含方法methodA定义为:

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

ObjectA是此类的实例。

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

ClassA.methodA(ObjectA, arg1, arg2)

self变量是指对象本身。

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

在此处输入图片说明

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

在此处输入图片说明

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

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

请参见下图:

在此处输入图片说明

我喜欢这个例子:

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: []

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

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 )

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

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

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

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

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

除已说明的所有其他原因外,它还允许更轻松地访问重写的方法;您可以调用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"

它的用法类似于 Java 中this关键字的用法,即提供对当前对象的引用。

与 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“面向对象编程”。一旦理解了这一点,您甚至不需要问这个问题:)。