【问题标题】:Variable Usage in Python Class DeclarationPython 类声明中的变量用法
【发布时间】:2012-10-16 23:05:11
【问题描述】:
这是 Zed Shaw 的“Learn Python the Hard Way”教程 40 中的代码 sn-p:
class Song(object):
def __init__(self, lyrics):
self.lyrics = lyrics
def sing_me_a_song(self):
for line in self.lyrics:
print line
为什么 Python 在定义“sing_me_a_song”函数时允许使用“self.lyrics”?是不是因为任何变量
在“init”下定义的也可以在同一个类的其他地方使用吗?
谢谢。
【问题讨论】:
标签:
python
class
variables
【解决方案1】:
实例变量
这称为实例变量。以self. 作为“前缀”定义的任何变量都可以在对象的任何方法中使用。通常此类变量是在__init__ 中创建的,因此可以从对象初始化的那一刻开始访问它们,尽管您可以在其他方法中定义实例变量。例如:
>>> class foo:
... def fun(self):
... self.heh=3
...
>>> f = foo()
>>> f.heh
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: foo instance has no attribute 'heh'
>>> f.fun()
>>> f.heh
3
注意在__init__ 之外初始化实例变量的危险;如果在您尝试访问它们之前未调用初始化它们的方法,则会出现错误。
类变量
不要与“类变量”混淆,后者是另一种类型的变量,可以被类的任何方法访问。可以为整个类设置类变量,而不仅仅是该类的特定对象。这是一个包含实例变量和类变量的示例类,以显示差异:
class MyClass:
classVar = "I'm a class var."
def __init__(self):
self.instanceVar = "I'm an instance var."
def fun(self):
methodVar = "I'm a method var; I cannot be accessed outside of this method."
self.instanceVar2 = "I'm another instance var, set outside of __init__."
关于“方法”与“函数”的注释
在您的问题中,您将sing_me_a_song 称为“函数”。实际上,它是Song 类的方法。这与常规的旧函数不同,因为它从根本上与类相关联,因此也与该类的对象相关联。
【解决方案2】:
当您定义 init 函数时,您会注意到第一个参数是“self”——这是对正在创建的对象的引用。当您执行“self.lyrics = Lyrics”时,这实际上是将值分配给对象的属性,而不是变量。
所以当你去其他地方访问它时,它是可见的——但不是因为它是一个变量!你的想法是对的,如果我们遵循正常的范围规则,它不应该是可见的。但是,它不是变量,任何代码都可以访问 self.lyrics 的值,只要它们有对对象的引用。
例如:
test = Song(["This is some lyrics."])
test.sing_me_a_song() #this works
print test.lyrics[0] #but so does this!
【解决方案3】:
根据代码,self.lyrics 在类的构造函数中定义。创建对象时总是首先调用构造函数。还有self.lyrics可以用在其他类方法中。
【解决方案4】:
self 用于引用正在调用该方法的Song 类的实际实例。例如,如果你这样做......
foo = Song("hello")
bar = Song("world")
然后foo.lyrics 设置为"hello",bar.lyrics 设置为"world"。如果您随后在其中一个实例上调用方法,就像这样......
foo.sing_me_a_song()
然后在将self 设置为foo 的情况下调用该方法,因此self.lyrics 会查找"hello",因为foo 中的实例将其lyrics 设置为"hello"。
【解决方案5】:
重要的是要意识到它不是一个类定义,它与 java 或 c++ 定义一个类的方式完全相同。
Self 是一个动态对象。无论是自己还是任何其他对象, myObj.newField = value 始终是有效的做法。
由于 init 在对象初始化时运行,因此有一个 self.lyrics 元素。
你可以有
def foo(self):
self.thing = "turtle"
然后在 foo 之后调用的任何函数中,您都可以引用 self.thing。 (这可能是一个非常糟糕的主意,但在语法上并没有错)。
【解决方案6】:
self 这个名字没什么特别的。在 python 中,对象的每个方法都会自动引用该对象作为它的第一个参数。
这意味着在__init__(构造函数)方法中,您在对象上设置属性lyrics。稍后,您可以调用sing_me_a_song,这将获得对具有歌词属性的同一对象的引用。