亚历克斯总结得很好,但令人惊讶的是,太简洁了。
首先,让我重申一下Alex文章的主要观点:
默认实现是无用的(很难想象有哪个实现不是无用的,但是是的)默认实现是无用的
这主要是一个意外,因为Python的默认值往往非常有用。但是,在这种情况下,为
1 | return"%s(%r)" % (self.__class__, self.__dict__) |
这样做太危险了(例如,如果对象相互引用,就太容易陷入无限递归)。所以Python退出了。注意,有一个默认值是true:如果定义了
简单地说,这意味着:几乎您实现的每个对象都应该有一个函数
让我直接说出来——我不相信调试器。我真的不知道如何使用调试器,而且从来没有认真地使用过。此外,我认为调试器的最大错误是它们的基本特性——我调试的大多数故障都发生在很久很久以前,在一个遥远的星系中。这意味着,我以宗教的热情相信伐木业。日志记录是任何一个体面的服务器系统的命脉。Python使日志记录变得很容易:使用一些特定于项目的包装器,您只需要一个
1 | log(INFO,"I am in the weird function and a is", a,"and b is", b,"but I got a null C — using default", default_c) |
但是您必须执行最后一步—确保您实现的每个对象都有一个有用的repr,这样代码才能正常工作。这就是为什么会出现eval:如果您有足够的信息so
注意:我使用的是上面的
具体地说,它并没有明确的意图——请注意
容器的
这似乎令人惊讶,不是吗?有一点,但是可读性如何
1 2 | [moshe is, 3, hello world, this is a list, oh I don't know, containing just 4 elements] |
是什么?不是很。具体地说,容器中的字符串会发现很容易干扰它的字符串表示。记住,面对模糊性,Python会抵制猜测的诱惑。如果您在打印列表时需要上述行为,只需
1 | print"[" +",".join(l) +"]" |
(你也许还能想出字典的用处。
总结
为您实现的任何类实现
我的经验法则是:
除非你特别采取行动,以确保否则,大多数类没有任何有益的结果:
1 2 3 4 5 6 7 | >>> class Sic(object): pass ... >>> print str(Sic()) <__main__.Sic object at 0x8b7d0> >>> print repr(Sic()) <__main__.Sic object at 0x8b7d0> >>> |
如您所见——没有区别,除了类和对象的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >>> class Sic(object): ... def __repr__(object): return 'foo' ... >>> print str(Sic()) foo >>> print repr(Sic()) foo >>> class Sic(object): ... def __str__(object): return 'foo' ... >>> print str(Sic()) foo >>> print repr(Sic()) <__main__.Sic object at 0x2617f0> >>> |
正如您所看到的,如果您覆盖
需要了解的其他重要花絮:内建容器上的
因此,我的建议是:集中精力使
如。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> s="""w'o"w""" >>> repr(s) '\'w\\'o"w\'' >>> str(s) 'w\'o"w' >>> eval(str(s))==s Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<string>", line 1 w'o"w ^ SyntaxError: EOL while scanning single-quoted string >>> eval(repr(s))==s True |
In short, the goal of
__repr__ is to be unambiguous and__str__ is to be
readable.
这里有一个很好的例子:
1 2 3 4 5 6 | >>> import datetime >>> today = datetime.datetime.now() >>> str(today) '2012-03-14 09:21:58.130922' >>> repr(today) 'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)' |
请阅读本文档:
repr(object) Return a string containing a printable representation of an object. This is the same value yielded by conversions (reverse
quotes). It is sometimes useful to be able to access this operation as
an ordinary function. For many types, this function makes an attempt
to return a string that would yield an object with the same value when
passed toeval() , otherwise the representation is a string enclosed in
angle brackets that contains the name of the type of the object
together with additional information often including the name and
address of the object. A class can control what this function returns
for its instances by defining a__repr__() method.
以下是str的文档:
str(object='') Return a string containing a nicely printable
representation of an object. For strings, this returns the string
itself. The difference withrepr(object) is thatstr(object) does not
always attempt to return a string that is acceptable toeval() ; its
goal is to return a printable string. If no argument is given, returns
the empty string,'' .
What is the difference between __str__ and__repr__ in Python?
如果缺少
因此,首先应该编写一个
在以后的任何时候,如果认为有必要,可以为用户可读的实例字符串表示形式编写
__str__
如果您打印一个对象,或者将其传递给
__repr__
因为它为
这是关于
1 2 3 4 5 | repr(...) repr(object) -> string Return the canonical string representation of the object. For most object types, eval(repr(object)) == object. |
也就是说,对于大多数对象,如果您输入由
默认对象
1 2 3 | def __repr__(self): return '<{0}.{1} object at {2}>'.format( self.__module__, type(self).__name__, hex(id(self))) |
这意味着在默认情况下,您将打印对象所在的模块、类名以及它在内存中的位置的十六进制表示——例如:
1 | <__main__.Foo object at 0x7f80665abdd0> |
这些信息不是很有用,但是没有办法精确地创建任何给定实例的规范表示,这总比什么都没有好,至少告诉我们如何在内存中惟一地标识它。
让我们看看使用Python shell和
1 | import datetime |
如果在shell中调用
1 2 | >>> datetime.datetime.now() datetime.datetime(2015, 1, 24, 20, 5, 36, 491180) |
如果我们打印一个datetime对象,我们会看到一个很好的人类可读(实际上是ISO)格式。这是由datetime的
1 2 | >>> print(datetime.datetime.now()) 2015-01-24 20:05:44.977951 |
重新创建我们丢失的对象很简单,因为我们没有通过复制和粘贴
1 2 3 | >>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180) >>> print(the_past) 2015-01-24 20:05:36.491180 |
我如何实现它们?
在开发过程中,如果可能的话,您希望能够以相同的状态复制对象。例如,datetime对象就是这样定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def __repr__(self): """Convert to formal string, for repr().""" L = [self._year, self._month, self._day, # These are never zero self._hour, self._minute, self._second, self._microsecond] if L[-1] == 0: del L[-1] if L[-1] == 0: del L[-1] s =",".join(map(str, L)) s ="%s(%s)" % ('datetime.' + self.__class__.__name__, s) if self._tzinfo is not None: assert s[-1:] ==")" s = s[:-1] +", tzinfo=%r" % self._tzinfo +")" return s |
如果希望对象具有更人性化的可读表示,可以接下来实现
1 2 3 | def __str__(self): "Convert to string, for str()." return self.isoformat(sep=' ') |
__repr__ = __str__ ?
这是对另一个建议设置
设置
只有在需要对象的文本表示时才需要
为您编写的对象定义
除了所有的答案,我想补充几点:-
1)当您在交互式python控制台简单地编写对象的名称并按enter键时,将调用
当您使用object with print语句时调用
3)如果缺少
4)
5)
6)
在Hans Petter Langtangen所著的《计算科学用Python脚本编写》一书的358页,它清楚地说明了这一点
所以,我更愿意把它们理解为
repr =复制str =字符串(表示形式)从用户的角度来看虽然这是我在学习python时产生的一个误解。
在同一页上还有一个虽小但很好的例子:
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | In [38]: str('s') Out[38]: 's' In [39]: repr('s') Out[39]:"'s'" In [40]: eval(str('s')) Traceback (most recent call last): File"<ipython-input-40-abd46c0c43e7>", line 1, in <module> eval(str('s')) File"<string>", line 1, in <module> NameError: name 's' is not defined In [41]: eval(repr('s')) Out[41]: 's' |
简单地说:
假设我想创建一个
所以我们可以创建一个简单的分数类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Fraction: def __init__(self, num, den): self.__num = num self.__den = den def __str__(self): return '(' + str(self.__num) + '/' + str(self.__den) + ')' def __repr__(self): return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')' f = Fraction(1,2) print('I want to represent the Fraction STRING as ' + str(f)) # (1/2) print('I want to represent the Fraction OBJECT as ', repr(f)) # Fraction (1,2) |
老实说,
因此,我建议设置
根据我的经验,要限定这一点,
来自effbot的http://pyref.infogami.com/_str__:
计算对象的"非正式"字符串表示形式。这与
其他答案中缺少的一个方面。这是真的,一般的模式是:
不幸的是,这种区分是有缺陷的,因为Python REPL和IPython都使用
的区别:
str ():
使对象可读为最终用户生成输出repr ():
需要生成对象的代码为开发人员生成输出优秀的答案已经涵盖了
由于这个原因,如果我有一个足够简单的
1 2 | def __repr__(self): return '{0} ({1})'.format(object.__repr__(self), str(self)) |
1 2 3 4 | "A basic requirement for a Python object is to provide usable string representations of itself, one used for debugging and logging, another for presentation to end users. That is why the special methods __repr__ and __str__ exist in the data model." |
书中:Fluent Python
1 2 3 4 | >>> print(decimal.Decimal(23) / decimal.Decimal("1.05")) 21.90476190476190476190476190 >>> decimal.Decimal(23) / decimal.Decimal("1.05") Decimal('21.90476190476190476190476190') |
当对decimal.Decimal(23) / deci- mal.Decimal("1.05")的结果调用print()时,将打印原始数字;这个输出是字符串形式的,可以用_str __()实现。如果我们简单地输入表达式,就会得到一个小数。十进制输出—这个输出是用……repr __()实现的表示形式。所有Python对象都有两种输出形式。字符串形式被设计成人类可读的。具象形式的设计目的是生成输出,如果将输出提供给Python解释器,则会(在可能的情况下)重新生成所表示的对象
简而言之:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Demo: def __repr__(self): return 'repr' def __str__(self): return 'str' demo = Demo() print(demo) # use __str__, output 'str' to stdout s = str(demo) # __str__ is used, return 'str' r = repr(demo) # __repr__ is used, return 'repr' import logging logger = logging.getLogger(logging.INFO) logger.info(demo) # use __str__, output 'str' to stdout from pprint import pprint, pformat pprint(demo) # use __repr__, output 'repr' to stdout result = pformat(demo) # use __repr__, result is string which value is 'str' |
所以更清晰从博客
str类似于toString。创建,以便您可以打印数据repr类似于序列化或pickle。如果我需要使用eval()来重新创建这个对象,我该如何做呢?
1 2 3 4 5 6 7 | >>> import datetime >>> now = datetime.datetime.now() >>> str(now) '2015-04-04 20:51:31.766862' >>> repr(now) 'datetime.datetime(2015, 4, 4, 20, 51, 31, 766862)' >>mydate = eval(repr(now)) |
One important thing to keep in mind is that container's
__str__ uses contained objects'__repr__ .
1 2 3 4 5 6 | >>> from datetime import datetime >>> from decimal import Decimal >>> print (Decimal('52'), datetime.now()) (Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000)) >>> str((Decimal('52'), datetime.now())) "(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))" |
Python倾向于不歧义而不是可读性,
直观地理解
看一个例子
1 2 3 | In [30]: str(datetime.datetime.now()) Out[30]: '2017-12-07 15:41:14.002752' Disguised in string form |
至于
1 2 3 | In [32]: datetime.datetime.now() Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769) Presence in real body which allows to be manipulated directly. |
我们可以方便地对
1 2 3 4 5 | In [33]: datetime.datetime.now() Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2 ...: 017, 12, 7, 15, 43, 27, 297769) Out[34]: datetime.timedelta(0, 222, 443752) |
如果在
1 2 | In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752' TypeError: unsupported operand type(s) for -: 'str' and 'str' |
只返回错误。
另一个例子。
1 2 3 4 5 | In [36]: str('string_body') Out[36]: 'string_body' # in string form In [37]: repr('real_body') Out[37]:"'real_body'" #its real body hide inside |
希望这能帮助你建立具体的基础来探索更多的答案。
除了