【问题标题】:What is different about Python class dictionaries?Python 类字典有什么不同?
【发布时间】:2012-04-22 08:46:43
【问题描述】:

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

【问题讨论】:

  • “愚蠢”的例子没有错(尽管如果你真的想拥抱这种文化,你应该尝试使用基于更知名的 Monty Python 草图的例子——这是标准的)。不过,您似乎确实有一些挥之不去的分号炎。
  • 嗨,迈克,这是来自 NU 的 Adam Forsyth,我们去年在 Norris 一起工作。最近怎么样? (我知道这不是一个社交网站,但我忍不住打招呼。)
  • 我很容易承认分号问题——我仍然把大部分时间花在 PHP 上(而且我正在学习 Javascript)。适当地注意到了 Monty Python - 下次我会尽量记住这一点 :) 再次感谢 Karl。嘿,亚当!好久不见。

标签: python oop class dictionary


【解决方案1】:

我意识到 name = "" 和 artist = "" 行(可能)是不必要的,但既然它们确实有效,我必须问:由于 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__ 并不特别;它可能会被自动调用并具有特定目的,但它与对象的交互方式与任何其他方法相同。 (因此即使在__init__ 中也需要self 参数。)

在您的__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 = {}

【讨论】:

  • things that are written inside the class block belong to the class, not to individual objects. 这正是我正在寻找的答案。剩下的只是锦上添花。谢谢!
  • 实际上是 C 和 Java 和 C# 以及所有其他在这方面很奇怪,因为在那里,class 语句中描述的数据属于对象(在为它们分配内存的意义上每个对象),但方法(C++ 用语中的成员函数)没有(因为这将是一种荒谬且无用的资源浪费)。这是因为那些语言仅将类视为对某些对象的描述(尽管您可以在 Java 和 C# 中显式调用“反射”),​​但 Python 将其视为本身就是一个对象。就像函数甚至模块。 :)
【解决方案2】:

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

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

通过在__init__() 中分配self 的属性来创建它们。

【讨论】:

    猜你喜欢
    • 2014-11-27
    • 2018-12-06
    • 2013-08-31
    • 2018-08-21
    • 2014-06-27
    • 2020-02-13
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    相关资源
    最近更新 更多