2

我在 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 = ""andartist = ""行(可能)是不必要的,但由于它们确实有效,我必须问:由于名称和艺术家字符串属性似乎在构造函数之外“初始化”工作正常;为什么没有周字典?

4

2 回答 2

4

我意识到 name = "" 和 artist = "" 行(可能)是不必要的,但既然它们确实有效,我必须问:由于 name 和艺术家字符串属性似乎在构造函数之外“初始化”正常工作;为什么没有周字典?

该代码完全有效,因为它们是不必要的。但是,这些不能“正常工作”,因为它们根本不“工作”,因为它们无关紧要,因为它们是不必要的。

如果您在其中设置了周字典,__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这样做: is的初始值'',它是一个字符串,而 Python 字符串没有提供就地修改它们的方法。当您重新分配一个包含字符串的变量时,您就是这样做的:重新分配。您使变量不再是旧对象的名称,而是开始成为新对象的名称。由于我们只能self.name通过赋值来影响Song.name,除非我们明确引用Song.name.

简单的解决方案是在 中设置属性__init__

self.week = {}
于 2012-04-10T03:06:23.043 回答
0

字符串是不可变的;你不能改变它们,只能重新绑定它们。

字典是可变的;它们可以更改,每个人都可以看到更改

self通过分配给within的属性来创建它们__init__()

于 2012-04-10T02:25:19.453 回答