我是一名新手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
__init__
中定义(例如
self.tricks =技巧)。我不指望它可以设置
self.tricks,因为它之前没有定义过。a.tricks = ['foo']
相比,为什么a.add_trick('roll over')
似乎表现得像预期的那样? add_trick
会产生不同的结果?*这是我到目前为止所阅读的内容,有更好的解释吗?
答案 0 :(得分:4)
class Dog:
tricks = []
这将tricks
定义为类上的属性,而不是任何实例。从某种意义上说,一个阶级财产是共享的。在所有类的实例之间。理想情况下,它应该通过类Dog.tricks
访问,但Python也允许通过实例进行访问,例如: a.tricks
或self.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
设置为某个内容之前,a
和b
共享类属性。您可能并不打算这样做 - 尝试下面的操作,这将为每个实例提供自己的tricks
:
class Dog:
def __init__(self, name):
self.name = name
self.tricks = []