【问题标题】:function and classes, usage of __str__函数和类,__str__ 的用法
【发布时间】:2013-03-28 03:10:07
【问题描述】:

我在函数、方法之间的交互方面遇到了一些问题,并且不确定如何使用内置函数__str__

首先,我有一个名为 vara 的类,它看起来像:

class vara(object):

    def __init__(self, kod, namn, pris, butikantal):
        self.kod = kod
        self.namn = namn
        self.pris = pris
        self.antal = butikantal

我有一个为 vara klass 创建对象列表的函数,如下所示:

def mina_varor():

  varor_fran_fil = open("varor.txt", "r")
  varulista = []
  for rad in varor_fran_fil:
      varje_vara1 = rad
      varje_vara2 = varje_vara1.split("/")
      varorna = vara(varje_vara2[0], varje_vara2[1], varje_vara2[2], varje_vara2[3])
      varulista.append(varorna)

  return(varulista)

现在我希望能够通过简单地键入对象的“kod”来访问此列表中的单个对象。但我在我的列表中找不到任何“kod”。看起来很奇怪,所以我尝试打印列表,结果如下:

[<__main__.vara object at 0x00000000031503C8>, <__main__.vara object at 0x00000000031507F0>, <__main__.vara object at 0x0000000003150710>, <__main__.vara object at 0x00000000031502B0>, <__main__.vara object at 0x00000000031505F8>, <__main__.vara object at 0x00000000031504E0>]

我查了一下,似乎 python 无法决定如何解释我的列表。我想我需要一个__str__ 方法来做到这一点,但是如果我想让我的__str__ 方法看起来像这样的话:

Name: Hat
Price: 150
Quantity: 100
Code: 223

?

【问题讨论】:

标签: python string list class function


【解决方案1】:

你可以像这样覆盖__repr__

class vara():
    def __init__(self, kod, namn, pris, butikantal):
        self.kod = kod
        self.namn = namn
        self.pris = pris
        self.antal = butikantal

    def __repr__(self):
        return 'Name: %s\nPrice: %s\nQuantity:%s\nCode: %s\n'\
               % (self.namn, self.pris, self.antal, self.kod)

输出:

>>> print([vara('223', 'Hat', '150', '100'), vara('115', 'Bla', '154', '200')])
[Name: Hat
Price: 150
Quantity:100
Code: 223
, Name: Bla
Price: 154
Quantity:200
Code: 115
]

编辑:

但正如@jedwards 所解释的,这是一种更好的方法来覆盖__str__,就像我为__repr__ 所做的那样并单独打印每个对象而不是打印整个列表。

【讨论】:

  • 这不是一个真正的好方法,但更像是一个懒惰的kluge。它建议无缘无故地违反__repr__()的合同/不讨论替代方案。
  • @jedwards 毫无疑问,您的答案是完整且内容丰富的,但 OP 可能正在寻找一些简单的方法来快速解决问题。我的回答没有错,是吗?无需投票反对其他答案来宣传您自己的答案。
  • 这不是为了宣传我自己的答案,但如果你想编辑你的答案(只需在某处添加一个空格,以便我可以撤销我的投票),我会为 CoI 撤销它。
  • @jedwards 无论如何我明白你的意思,多解释一点也无妨。 :)
【解决方案2】:

问题 1:打印容器时没有调用 __str__()

并不是 Python 不能解释你的列表,而是它不知道你期望它如何显示。

如果您想做类似的事情,请实现 __str__ 方法

print(varulista[0])

类似下面的内容会为您提供您对该列表条目的期望:

def __str__(self):
    s  = "Name:    %s\n" % self.namn
    s += "Price:   %s\n" % self.pris
    s += "Quantity:%s\n" % self.antal
    s += "Code:    %s\n" % self.kod

但如果你想让print(varulista) 有意义,你还必须实现__repr__ 方法,因为varulista 是一个列表,而在打印它时,Python 会查找__repr__ 方法。

话虽如此,__repr__ 的想法是能够将其传递回eval() 并创建一个等效对象。所以你可以选择以下两种方式之一:

1.忽略__repr__()/eval()交互

在这种情况下,只需实现 __repr__() 即可。请记住,当它是您正在打印的容器中的项目时,将调用此方法,因此将输出保持在单行可能会有所帮助。只要知道除非您在__repr__() 输出中明确表示对象的状态,否则您将无法使用eval() 在“未来”重新创建等效对象。

2。 (首选选项,IMO)正确实施__repr__(),如果您不喜欢它的外观,请不要打印容器。

如果输出喜欢

[Item{Name:"Hat",Price:150,Quantity:100,Code:223},Item{Name:"Shirt",Price:450,Quantity:10,Code:225}]

太不友好了,因为你必须如何实现__repr()__,只是不要打印容器。换句话说,不要使用

print(varulista)

而是使用

for item in varulista: print item

它将调用您定义的__str__() 方法,对人类友好的方法。

编辑: @bernie 与 a great answer by @AlexMartelli 的链接关于 __str____repr__ 之间的区别值得链接两次。


问题 2:能够通过其代码访问列表元素

你说

现在我希望能够通过简单地键入对象的“kod”来访问此列表中的单个对象。但我在我的列表中找不到任何“kod”。看起来很奇怪,所以我尝试打印列表,结果如下:

这里有两个主要选项。 (1) 使用以项目代码为关键字的字典。 (2) 使用列表推导在列表中搜索代码。我只展示 (1),因为我认为这是一个更好的选择。

选项 1:使用键入项目代码的字典

考虑这段代码:

# Define a convenience function to add items to the dictionary
def add_item(d,i): d[i.kod] = i

# Create a new dictionary
items = {}

# Add items to dictionary
add_item(items, vara(223, "Hat", 150, 100))
add_item(items, vara(225, "Shirt", 450, 10))

您现在可以访问items 字典中的任何已定义项目,如下所示:

items[223] #<-- This is the "Hat" item
items[225] #<-- This is the "Shirt" item

【讨论】:

  • 哇,对于像我这样几乎是 python 初学者的人来说,帮助和解释都很好!我只有两件事想问你。 1:我喜欢在 varulista 中使用 for item 的想法,但你说这样做,我会调用 __str__() 方法。我没有看到你在任何地方调用它并且有点困惑。如果我只做 for 循环,我不会调用 __str__() 方法。我必须有更多的代码,对吧? 2:在第二部分,关于做字典。看来我必须将每个对象添加到字典中。我不能简单地做一个for循环,添加我列表的每一行
  • 1.当 Python 尝试将 vara 对象转换为字符串时,__str__() 会隐式调用它。所以你不需要调用它,print() 在这种情况下会为你做。
  • 2.是的,您必须以某种方式添加每个项目。我的建议是跳过使用列表的中间步骤,但如果你有一个列表,你描述的 for 循环就可以了。可能:for item in varulista: add_item(items, item) 甚至只是for item in varulista: items[item.kod] = item,第二个选项消除了add_item 便利功能的使用。
  • 确实有很大帮助!必须尝试这些,在我进行一些实验后会回来提供一些反馈。非常感谢!
  • 就像一个魅力,推荐有类似问题的人尝试这些代码!
猜你喜欢
  • 2017-05-01
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-11
  • 2014-05-12
  • 2017-07-16
  • 1970-01-01
相关资源
最近更新 更多