python中的类和self:实例和类变量

时间:2018-03-17 01:46:36

标签: python python-3.x class oop instance

我是一名新手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
  • 为什么self.tricks存在?它从未在__init__中定义(例如 self.tricks =技巧)。我不指望它可以设置 self.tricks,因为它之前没有定义过。
  • 为什么我的方法不会产生不同的答案?也就是说,与a.tricks = ['foo']相比,为什么a.add_trick('roll over')似乎表现得像预期的那样?
  • 看起来操作顺序很重要。为什么在设置a.trick之前调用add_trick会产生不同的结果?

*这是我到目前为止所阅读的内容,有更好的解释吗?

1 个答案:

答案 0 :(得分:4)

class Dog:
    tricks = []

这将tricks定义为上的属性,而不是任何实例。从某种意义上说,一个阶级财产是共享的。在所有类的实例之间。理想情况下,它应该通过类Dog.tricks访问,但Python也允许通过实例进行访问,例如: a.tricksself.tricks。规则是,如果x是实例,x.y将引用实例y的属性x(如果存在),否则属性y x的课程。

a.tricks = ['foo']

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

因此,您所看到的行为是因为在您明确将a.tricks设置为某个内容之前,ab 共享类属性。您可能并不打算这样做 - 尝试下面的操作,这将为每个实例提供自己的tricks

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