Python 3中是否有一种方法可以以编程方式递归地调用私有成员变量唯一的__str__
函数?像这样:
class A:
def __str__(self):
return "A"
class B:
def __str__(self):
return "B"
class C:
def __init__(self):
self._A = A()
self._B = B()
def __str__(self):
for var in vars(self):
return str(var)
呼叫个别私人成员时,它可以正常工作。但是,想要一种动态地执行此操作的方法。
非常感谢。
答案 0 :(得分:2)
vars
函数返回一个字典,其中的键是变量名(作为字符串),值是变量的值。因此,迭代这些值应该可以。
class A:
def __str__(self):
return "A"
class B:
def __str__(self):
return "B"
class C:
def __init__(self):
self._A = A()
self._B = B()
def __str__(self):
output = ""
for _,var in vars(self).items(): #Iterate over the values
output += str(var) #Use the str() function here to make the object return its string form
return output #Need to return instead of print since that is what the __str__() function should do
如果需要,可以在值之间添加某种分隔符(例如\n
)。只需将str(var)
替换为str(var) + "\n"
。
答案 1 :(得分:1)
您也可以使用字典键; vars()
是self.__dict__
:
>>> class A:
... def __str__(self):
... return self.__class__.__name__
...
>>> class B:
... def __str__(self):
... return self.__class__.__name__
...
>>> str(A())
'A'
>>> repr(A()) # "long-form" the hex-string is id()
'<__main__.A object at 0x10f65a908>'
>>> class C:
... def __init__(self):
... self.A = A()
... self.B = B()
... def __str__(self):
... return '\n'.join(self.__dict__)
...
>>> C()
<__main__.C object at 0x10f65aa58>
>>> print(C()) # Uses str(C())
A
B
vars(self)
实际上是self
。反过来,self.__dict__
是用于存储对象(可写)属性的dict
。
>>> C().__dict__
{'A': <__main__.A object at 0x10f65aa90>, 'B': <__main__.B object at 0x10f65aac8>}
签名为'\n'.join(iterable)
,当您遍历字典时,您遍历其键,在这种情况下就足够了。
我不确定(Python 3.7+)数据类在这里是否更容易解决。这是因为据我所知,它们会自动实现__repr__()
而不是__str__()
:
>>> from dataclasses import dataclass
>>>
>>> @dataclass
... class C:
... _A: object = A()
... _B: object = B()
...
>>> c = C() # still uses repr() for each field
>>> str(c)
'C(_A=<__main__.A object at 0x10f373828>, _B=<__main__.B object at 0x10f373940>)'
换句话说,您需要将A.__str__
替换为A.__repr__
(与B
相同,对于这些内容,您可能一开始就不想这样做两课。
答案 2 :(得分:0)
您确定不应该使用__repr__
吗?
无论如何,这是一个使用attrs
的示例,因为我被困在Python 3.5上。使用dataclasses
,它将以类似的方式工作。
import attr
class A:
def __str__(self):
return 'A'
class B:
def __str__(self):
return 'B'
@attr.s
class C:
a = attr.ib(default=attr.Factory(A))
b = attr.ib(default=attr.Factory(B))
if __name__ == '__main__':
c = C()
print(c) # __str__ defaults to __repr__
def __str__(self):
bits = ['<C']
for a in self.__attrs_attrs__:
bits.append(' %s=%s' % (a.name, getattr(self, a.name)))
bits.append('>')
return ''.join(bits)
C.__str__ = __str__
print(c) # custom __str__