Python “str”和“repr”之间有什么区别?
Python中的Python “str”和“repr”之间有什么区别?,python,magic-methods,repr,Python,Magic Methods,Repr,Python中的\uuu str\uuu和\uu repr\uuu有什么区别?来自effbot: \uuuu str\uuuuu计算对象的“非正式”字符串表示形式。这与\uuuuu repr\uuuuu不同,因为它不必是有效的Python表达式:可以使用更方便或简洁的表示形式。”\uuuu repr\uuuu:python对象的表示形式通常eval会将其转换回该对象 \uuuu str\uuuuu:是您认为文本形式的对象 e、 g >>s=“”w'o“w”“” >>>报告员(s) “\'w\\'
\uuu str\uuu
和\uu repr\uuu
有什么区别?来自effbot:
\uuuu str\uuuuu
计算对象的“非正式”字符串表示形式。这与\uuuuu repr\uuuuu
不同,因为它不必是有效的Python表达式:可以使用更方便或简洁的表示形式。”\uuuu repr\uuuu
:python对象的表示形式通常eval会将其转换回该对象
\uuuu str\uuuuu
:是您认为文本形式的对象
e、 g
>>s=“”w'o“w”“”
>>>报告员(s)
“\'w\\'o”w\'
>>>str(s)
“w”“o”“w”
>>>eval(str(s))==s
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第1行
w'o“w
^
SyntaxError:扫描单引号字符串时下线
>>>评估(报告)=s
真的
除非您特别采取行动以确保其他方面,否则大多数类在以下两方面都没有有用的结果:
>>> class Sic(object): pass
...
>>> print str(Sic())
<__main__.Sic object at 0x8b7d0>
>>> print repr(Sic())
<__main__.Sic object at 0x8b7d0>
>>>
如您所见,如果覆盖\uuuuu repr\uuuu
,它也用于\uuuu str\uuuu
,但反之亦然
需要了解的其他重要花絮:内置容器上的\uuuuu str\uuuu
对其包含的项目使用\uuuu repr\uuuu
,而不是\uuu str\uuuu
。而且,尽管在典型的文档中可以找到关于这个主题的词语,但几乎没有人愿意将对象的\uuuu repr\uuuu
变成一个字符串,而eval
可以用来构建一个相等的对象(这太难了,而且不知道相关模块实际上是如何导入的,这实际上是不可能的)
因此,我的建议是:集中精力使
\uuuuu str\uuuuu
具有合理的人类可读性,并尽可能使\uuuuu repr\uuuuuu
尽可能明确,即使这会干扰模糊的无法实现的目标,即使\uuuu repr\uuuuuu
的返回值可以作为\uu eval\uuucode>的输入 我的经验法则:\uuuu repr\uuu
是给开发者的,\uu str\uuu
是给客户的。总结得很好,但令人惊讶的是,太简洁了
首先,让我重申以下要点:
- 默认的实现是无用的(很难想象有一个不是,但是是的)
\uuuu repr\uuuu
目标是明确无误
\uuuu str\uuuu
目标是可读的
- 容器的
\uuuu str\uuuu
使用包含的对象“\uuuuu repr\uuuu
默认实现是无用的
这主要是一个惊喜,因为Python的默认值往往相当有用。但是,在这种情况下,\uuuu repr\uuu
的默认值如下:
return "%s(%r)" % (self.__class__, self.__dict__)
太危险了(例如,如果对象相互引用,就很容易陷入无限递归)。所以蟒蛇逃走了。请注意,有一个默认值为true:如果定义了\uuuu repr\uuuu
,而未定义\uuuu str\uuuu
,则对象的行为将类似于\uuuuu str\uuu=\uuuuu repr\uu
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
print('__str__ called')
return self.name
p=Person('ali',20)
简单地说,这意味着:几乎您实现的每个对象都应该有一个可用于理解对象的功能性\uu repr\uu
。实现\uuuu str\uuuu
是可选的:如果您需要“漂亮打印”功能(例如,由报表生成器使用),请执行此操作
的目标是明确无误
让我直截了当地说出来——我不相信调试器。我真的不知道如何使用任何调试器,也从未认真使用过。此外,我相信调试器的最大缺陷是它们的基本特性——我调试的大多数故障都发生在很久以前,在遥远的银河系中。这意味着我怀着宗教的热情相信伐木。日志记录是任何体面的fire and forget服务器系统的生命线。Python使日志记录变得很容易:使用一些特定于项目的包装器,您所需要的只是一个
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”的问题:如果你有足够的信息,那么eval(repr(c))==c
,这意味着你知道关于c
的一切。如果这很容易,至少以一种模糊的方式,那么就去做吧。如果没有,请确保您有足够的关于c
的信息。我通常使用类似eval的格式:“MyClass(this=%r,that=%r)”%(self.this,self.that)
。这并不意味着您可以实际构造MyClass,或者这些都是正确的构造函数参数,但它是一种有用的形式,可以表示“这就是您需要了解的有关此实例的所有信息”
注意:我使用了上面的%r
,而不是%s
。您总是希望在\uuu repr\uuu
实现中使用repr()
[或%r
格式化字符,等价地],否则您将无法实现repr的目标。您希望能够区分MyClass(3)
和MyClass(“3”)
代码的目标是可读性
具体地说,它并不打算明确-注意str(3)==str(“3”)
。同样,如果您实现一个IP抽象,让它的str看起来像192.168.1.1就可以了。在实现日期/时间抽象时,str可以是“2010/4/12 15:35:22”,等等。目标是以用户而不是程序员希望阅读的方式表示它。切掉无用的数字,假装是其他类-只要它支持可读性,这就是一种改进
容器的\uuuu str\uuuuuuuuuuuuuuuuuuuu
使用包含对象的\uuuuuuu repr\uuuuuuuuuu
这似乎令人惊讶,不是吗?它有点小,但是如果它使用他们的\uuuu str\uuuu
,它的可读性会有多高
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
不太好。具体来说,容器中的字符串很容易干扰其字符串表示。
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
print "[" + ", ".join(l) + "]"
>>> 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(...)
repr(object) -> string
Return the canonical string representation of the object.
For most object types, eval(repr(object)) == object.
def __repr__(self):
return '<{0}.{1} object at {2}>'.format(
self.__module__, type(self).__name__, hex(id(self)))
<__main__.Foo object at 0x7f80665abdd0>
import datetime
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951
>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180
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 = "%s.%s(%s)" % (self.__class__.__module__,
self.__class__.__qualname__,
", ".join(map(str, L)))
if self._tzinfo is not None:
assert s[-1:] == ")"
s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
if self._fold:
assert s[-1:] == ")"
s = s[:-1] + ", fold=1)"
return s
def __str__(self):
"Convert to string, for str()."
return self.isoformat(sep=' ')
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')
def __repr__(self):
return '{0} ({1})'.format(object.__repr__(self), str(self))
>>> 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))"
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)
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'
In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form
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.
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)
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'
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
class C1:pass
class C2:
def __str__(self):
return str(f"{self.__class__.__name__} class str ")
class C3:
def __repr__(self):
return str(f"{self.__class__.__name__} class repr")
class C4:
def __str__(self):
return str(f"{self.__class__.__name__} class str ")
def __repr__(self):
return str(f"{self.__class__.__name__} class repr")
ci1 = C1()
ci2 = C2()
ci3 = C3()
ci4 = C4()
print(ci1) #<__main__.C1 object at 0x0000024C44A80C18>
print(str(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(repr(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(ci2) #C2 class str
print(str(ci2)) #C2 class str
print(repr(ci2)) #<__main__.C2 object at 0x0000024C44AE12E8>
print(ci3) #C3 class repr
print(str(ci3)) #C3 class repr
print(repr(ci3)) #C3 class repr
print(ci4) #C4 class str
print(str(ci4)) #C4 class str
print(repr(ci4)) #C4 class repr
>>> x, y = 'foo', 123
>>> str(x), str(y)
('foo', '123')
>>> 123
123
>>> foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>> eval('123')
123
>>> eval('foo')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'foo' is not defined
>>> repr(x), repr(y)
("'foo'", '123')
>>> 123
123
>>> 'foo'
'foo'
>>> eval('123')
123
>>> eval("'foo'")
'foo'
class Person:
pass
p=Person()
<__main__.Person object at 0x7fb2604f03a0>
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def __repr__(self):
print("__repr__ called")
return f"Person(name='{self.name}',age={self.age})"
p=Person("ali",20)
__repr__ called
Person(name='ali',age=20)
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
print('__repr__ called')
return f"Person(name='{self.name}, age=self.age')"
def __str__(self):
print('__str__ called')
return self.name
p=Person("ali",20)
__str__ called
ali
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
print('__str__ called')
return self.name
p=Person('ali',20)
__str__ called
ali