类 和 python 中的自我:实例和 class 变量

Classes and self in python: instance and class variables

我是一名新手 Python 程序员,对 OOP 和 类 中对 self 的需求感到非常困惑。我已经阅读了许多试图揭开它神秘面纱的 SO 帖子、博客* 等,但可以在这种特定情况下使用一些帮助。

下面的场景基于 Python2 tutorial on Class and Instance Variables。我将以我的例子开头,然后在下面提出明确的问题。

首先,我直接设置tricks,然后使用add_trick方法:

class Dog:

    tricks = []      

    def __init__(self, name):
        self.name = name

    def add_trick(self, trick):
        self.tricks.append(trick)

    def print_self_tricks(self):
        print(self.tricks)

a = Dog('spencer')
b = Dog('rex')

a.tricks = ['foo'] # How is this even possible? Where did I define self.tricks? 

a.print_self_tricks()
['foo']    # Ok, the below results make sense
b.print_self_tricks()
[]
a.tricks
['foo']
b.tricks
[]

a.add_trick('jump')

a.print_self_tricks()
['foo', 'jump']
b.print_self_tricks()
[]          # Great, as expected
a.tricks
['foo', 'jump']
b.tricks
[]          # Great, as expected

现在,完全相同的设置,但执行顺序不同:add_trick 在直接设置 trick 之前。

class Dog:

    tricks = []      

    def __init__(self, name):
        self.name = name

    def add_trick(self, trick):
        self.tricks.append(trick)

    def print_self_tricks(self):
        print(self.tricks)

a = Dog('spencer')
b = Dog('rex')

a.add_trick('jump')

a.print_self_tricks()
['jump']
b.print_self_tricks() 
['jump']    # Welp, that's not expected. 
a.tricks
['jump']
b.tricks
['jump']    # Welp, that's not expected. 

a.tricks = ['foo']

a.print_self_tricks()
['foo']
b.print_self_tricks() 
['jump']    # Great, but inconsistent with the behavior above resulting from a.add_trick
a.tricks
['foo']
b.tricks
['jump']    # Great, but inconsistent with the behavior above resulting from a.add_trick

*这是我目前读到的内容,还有更好的解释吗?

class Dog:
    tricks = []

这将 tricks 定义为 class 上的 属性,而不是任何 实例 . class 属性 在某种意义上是 "shared" 在 class 的所有实例之间。理想情况下应该通过 class: Dog.tricks 访问它,但是 Python 也允许通过实例访问,例如a.tricksself.tricks。规则是,如果x是一个实例,x.y将引用实例x的属性y(如果存在),否则y的属性y x 的 class.

a.tricks = ['foo']

Python 是一种 dynamically-typed 语言,不需要预先声明 class 元素、属性或变量。此语句 a 引用的 Dog 实例上创建 一个属性,并使其引用一个字符串列表。在此之前,a.tricks 将解析为 class 属性引用的 still-empty 列表,但在此之后,a.tricks 将解析为 ['foo']tricks 尚未在 b 上设置,因此 b.tricks 仍解析为与 Dog.tricks 相同的内容。

所以你看到的行为是因为在你明确设置 a.tricks 之前,ab 共享 class 属性。你可能不打算这样做 - 试试下面的方法,它会给每个实例自己的 tricks:

class Dog:
    def __init__(self, name):
        self.name = name
        self.tricks = []