我在Python 2.7中遇到类属性问题,设法找到解决方案,但我不明白。
在下面的设计代码中,我希望每首歌都有自己的字典,其中包含所提及的一周中的日期歌词。
class Song:
name = ""
artist = ""
# If I comment this line and uncomment the one in the constructor, it works right
week = {}
def set_monday( self, lyric ):
self.week[ "Monday" ] = lyric;
.
. # silly, I know
.
def set_friday( self, lyric ):
self.week[ "Friday" ] = lyric;
def show_week( self ):
print self.week
def __init__(self, name, artist):
self.name = name
self.artist = artist
# Uncomment the line below to fix this
# self.week = {}
def main():
songs = {}
friday_im_in_love = Song( "Friday I'm in Love", "the Cure" )
friday_im_in_love.set_monday( "Monday you can fall apart" )
friday_im_in_love.set_tuesday( "Tuesday can break my heart" )
friday_im_in_love.set_wednesday( "Wednesday can break my heart" )
friday_im_in_love.set_thursday( "Thursday doesn't even start" )
friday_im_in_love.set_friday( "Friday I'm in love" )
songs[ "Friday I'm in Love" ] = friday_im_in_love
manic_monday = Song( "Manic Monday", "the Bangles" )
manic_monday.set_monday( "Just another manic Monday" )
songs[ "Manic Monday" ] = manic_monday
for song in songs:
# This shows the correct name and artist
print songs[song].name + " by " + songs[song].artist
# The dictionary is incorrect, though.
songs[song].show_week()
if __name__ == '__main__':
main()
除了运行上面的代码时,输出如下所示:
Manic Monday by the Bangles
{'Friday': "Friday I'm in love", 'Tuesday': 'Tuesday can break my heart', 'Thursday': "Thursday doesn't even start", 'Wednesday': 'Wednesday can break my heart', 'Monday': 'Just another manic Monday'}
Friday I'm in Love by the Cure
{'Friday': "Friday I'm in love", 'Tuesday': 'Tuesday can break my heart', 'Thursday': "Thursday doesn't even start", 'Wednesday': 'Wednesday can break my heart', 'Monday': 'Just another manic Monday'}
这两本字典看起来都不像我期望的那样。回到代码,如果我在评论week = {}
之前评论,并在构造函数中取消注释self.week={}
,那么字典会按照我期望的方式出现。
Manic Monday by the Bangles
{'Monday': 'Just another manic Monday'}
Friday I'm in Love by the Cure
{'Friday': "Friday I'm in love", 'Tuesday': 'Tuesday can break my heart', 'Thursday': "Thursday doesn't even start", 'Wednesday': 'Wednesday can break my heart', 'Monday': 'Monday you can fall apart'}
为什么会这样?
我意识到name = ""
和artist = ""
行(可能)是不必要的,但由于他们做工作,我必须要问:因为名称和艺术家字符串属性似乎有效精简“初始化”在构造函数之外;为什么不是周词典?
答案 0 :(得分:4)
我意识到name =“”和artist =“”行是(可能)不必要但是因为它们确实有效,我必须要问:因为名称和艺术家字符串属性似乎在构造函数之外工作得很好“初始化”;为什么不是周词典?
代码正好,因为它们是不必要的。但是,行并不“正常”,因为它们根本不“工作”因为它们是不相关的,因为它们是不必要的。
如果您在__init__
中设置周词典,即使您在班级中留下week = {}
行也会有效,因为相同的机制会启动。
让我们更仔细地看一下:
# If I comment this line and uncomment the one in the constructor, it works right
week = {}
Python遵循一个非常简单的规则:在class
块内编写的内容属于类,而不属于单个对象。要将某些内容附加到名为self
的对象,请指定其中一个self.attributes
。在这方面,__init__
并不特别;它可以自动调用并具有特定目的,但它与对象的交互方式与任何其他方法相同。 (因此即使在self
中也需要__init__
参数。)
在__init__
中,您可以:
self.name = name
self.artist = artist
这会将属性附加到类的每个对象(因为每个对象都被__init__
调用),隐藏类中的那个。当属性查找时,会在类和对象中查找它们(如果在对象中找不到它们),但是当它们被分配时 ,它们被简单地分配给你说要分配给它的东西。 (要修改Song
属性,即使在方法内也可以使用Song.whatever = 42
。)
在类中创建属性时也会出现问题,并且也不会为实例分配属性。请注意,__init__
并不特殊;您可以稍后创建该类的新属性。
现在,由于__init__
并不特殊,我们假设我们在__init__
内执行其中一个示例函数的工作:
self.week["Friday"] = "gotta get down"
你看到了区别吗? week["Friday"]
不是属性名称; week
是。所以我们无法创建像这样的新属性。相反,我们修改 现有对象,该对象被查找为self.week
。哪个在类中找到一个,因为该对象没有。当我们再次查看self.week
时,即使self
与Song
不同,我们也会看到此更改,因为只有一个Song.week
。
如果我们用修饰现有对象的东西替换self.name = name
,那么我们会看到相同的行为。但是,我们不能实际执行此操作:self.name
的初始值为''
,这是一个字符串,Python字符串提供无法修改它们就地。当您重新分配给包含字符串的变量时,您可以这样做:重新分配。您导致变量不再是旧对象的名称,并开始成为新对象的名称。由于我们只能通过分配影响self.name
,因此除非我们明确提及Song.name
,否则我们无法影响Song.name
。
简单的解决方案是在__init__
中设置属性:
self.week = {}
答案 1 :(得分:0)
字符串是不可变的;你不能改变它们,只能重新绑定它们。
字典是可变的;它们可以更改,每个人都可以看到更改。
通过在self
内分配__init__()
的属性来创建它们。