Python-为什么在类中使用“自我”?


82

这两个类别有何不同?

class A():
    x=3

class B():
    def __init__(self):
        self.x=3

有什么明显的区别吗?


6
不,不是重复的。

1
@hop:有趣的断言,但是您没有提供任何示例或证据来证明它不是重复的。为什么这么说
S.Lott

2
@ S.Lott-嗯?另一个问题是问为什么我们需要显式地传递自我。这是由于类变量和实例变量而引起的差异。
Dana

1
@ S.Lott这不是同一个问题。在问之前,我什至看过那个。
ryeguy

2
@ S.Lott:68282是一个无用的问题,它说明为什么必须显式将self作为方法的第一个参数;这个问题询问类成员和实例成员之间的区别。S.Lott,我真的很喜欢您对SO的贡献,但是这次您错了。

Answers:


137

A.x是一个类变量Bself.x是一个实例变量

Ax被实例之间共享。

用可以像列表这样修改的东西来证明区别是比较容易的:

#!/usr/bin/env python

class A:
    x = []
    def add(self):
        self.x.append(1)

class B:
    def __init__(self):
        self.x = []
    def add(self):
        self.x.append(1)

x = A()
y = A()
x.add()
y.add()
print("A's x:", x.x)

x = B()
y = B()
x.add()
y.add()
print("B's x:", x.x)

输出量

A's x: [1, 1]
B's x: [1]

8
也许还发布了脚本的输出,那么您无需复制并自行运行就可以看到区别……
Martin

7
我添加了输出。
UnkwnTech

2
那么,python的自我等同于Java的自我吗?请原谅一下
Jean Azzopardi

2
@Jean-是的-self必须只是实例方法的第一个参数的常规名称-python显式地将实例方法的当前实例作为实例方法的第一个参数传递。但这与Java的功能相同
Douglas Leeder

@Jean Azzopardi:自我几乎就像Java(和C ++)一样。自我是必须的;这有时是Java编译器(有时是必需的)提出的
。– S.Lott

55

正如一个侧面说明:self实际上只是一个随机选择的话,每个人都使用,但你也可以使用thisfoomyself或者其他任何你想要的,它只是一个类每一个非静态方法的第一个参数。这意味着单词self不是语言构造,而只是名称:

>>> class A:
...     def __init__(s):
...        s.bla = 2
... 
>>> 
>>> a = A()
>>> a.bla
2

1
为什么这是答案而不是评论
Gabriel Petersson

23

Ax是一个类变量,并且将在A的所有实例之间共享,除非在实例中被特别覆盖。Bx是一个实例变量,并且B的每个实例都有其自己的版本。

我希望以下Python示例可以阐明这一点:


    >>> class Foo():
    ...     i = 3
    ...     def bar(self):
    ...             print 'Foo.i is', Foo.i
    ...             print 'self.i is', self.i
    ... 
    >>> f = Foo() # Create an instance of the Foo class
    >>> f.bar()
    Foo.i is 3
    self.i is 3
    >>> Foo.i = 5 # Change the global value of Foo.i over all instances
    >>> f.bar()
    Foo.i is 5
    self.i is 5
    >>> f.i = 3 # Override this instance's definition of i
    >>> f.bar()
    Foo.i is 5
    self.i is 3

16

我曾经用这个例子来解释

# By TMOTTM

class Machine:

    # Class Variable counts how many machines have been created.
    # The value is the same for all objects of this class.
    counter = 0

    def __init__(self):

        # Notice: no 'self'.
        Machine.counter += 1

        # Instance variable.
        # Different for every object of the class.
        self.id = Machine.counter

if __name__ == '__main__':
    machine1 = Machine()
    machine2 = Machine()
    machine3 = Machine()

    #The value is different for all objects.
    print 'machine1.id', machine1.id
    print 'machine2.id', machine2.id
    print 'machine3.id', machine3.id

    #The value is the same for all objects.
    print 'machine1.counter', machine1.counter
    print 'machine2.counter', machine2.counter
    print 'machine3.counter', machine3.counter

然后输出将

machine1.id 1
machine2.id 2
machine3.id 3

machine1.counter 3
machine2.counter 3
machine3.counter 3

3

我刚刚开始学习Python,这也让我感到困惑。为了弄清楚总体上它们是如何工作的,我想到了以下非常简单的代码:

# Create a class with a variable inside and an instance of that class
class One:
    color = 'green'

obj2 = One()


# Here we create a global variable(outside a class suite).
color = 'blue'         

# Create a second class and a local variable inside this class.       
class Two:             
    color = "red"

    # Define 3 methods. The only difference between them is the "color" part.
    def out(self):     
        print(self.color + '!')

    def out2(self):
        print(color + '!')

    def out3(self):
        print(obj2.color + '!')

# Create an object of the class One
obj = Two()

当我们打电话给out()我们时:

>>> obj.out()

red!

当我们打电话给out2()

>>> obj.out2()

blue!

当我们打电话给out3()

>>> obj.out3()

green!

因此,在第一种方法中,self指定Python应该使用变量(属性),该变量“属于”我们创建的类对象,而不是全局类(在类外部)。因此它使用color = "red"。在该方法中,Python隐式替换self了我们创建的对象的名称(obj)。self.color意思是“我收到color="red"来自obj

在第二种方法中,没有self指定要从中获取颜色的对象,因此它获得了全局对象color = 'blue'

在第三个方法中,self我们代替了使用obj2-要获取的另一个对象的名称color。它得到color = 'green'

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.