【问题标题】:Any way to add **kwargs to __str__()'s signature of an object?有什么方法可以将 **kwargs 添加到 __str__() 的对象签名中?
【发布时间】:2016-06-03 14:15:37
【问题描述】:

我希望能够更改__str__() 的输出,并希望为此添加**kwargs。

问题:似乎无法更改函数的签名。

例如:

#!/usr/bin/env python3

class my_printable_obj(object):

    def __init__(self, s):
        self.content = s

    def __str__(self, **kwargs):
        fancy = kwargs.get('fancy', '')
        return str(self.content) + fancy



M = my_printable_obj("Something to print")

print(str(M))
print(str(M, fancy=' + a fancy part'))

输出:

$ ./test_script3str.py 
Something to print
Traceback (most recent call last):
  File "./test_script3str.py", line 17, in <module>
    print(str(M, fancy=' + a fancy part'))
TypeError: 'fancy' is an invalid keyword argument for this function

我注意到,尽管有 TypeError 消息,python 确实使用了my_printable_obj.__str__()(在__str__() 的开头添加一个print('here') 可以轻松观察到这一点)。

是否有解决方案,或者由于某种原因不可能?那么我是否应该更好地定义另一个函数,例如 into_str(self, **kwargs) 并使用 M.into_str(fancy=' something more') 而不是 __str__()?

注意:写这个:

def __str__(self, fancy=''):
    return str(self.content) + fancy

给出完全相同的错误。

【问题讨论】:

  • 您可以将**kwargs 添加到.__str__() 的实现中,但不能添加到str() 的标准实现中。考虑使用具有更宽接口的单独方法,例如.fancyStr();你也可以让.__str__() 调用它。
  • 是的,但我可以使用像str(M, fancy=' + a fancy part') 这样的东西吗?我的意思是,那时可以调用str(M),但我必须直接使用M.fancyStr(fancy='...')才能使用这个kwarg?
  • 如果您想根据对象的属性呈现单独的字符串,我会使用单独的方法。如果您不关心对象的属性,我会完全在对象之外进行,也许使用装饰器模式,也许只使用纯字符串连接。我不确定您为什么要将每个人对str() 的期望更改为您的具体示例:)
  • 您可以制作自己的str (mystr) 版本,它接受参数并将它们传递给__str__。

标签: python string python-3.x signature keyword-argument


【解决方案1】:

您使用 kwarg 调用的函数是 str (the inbuilt function)。

str() 确实在您的对象上调用了__str__ 方法。


也许你要找的是__format__

>>> class MyPrintableObj(object):

    def __init__(self, s):
        self.content = s

    def __format__(self, formatstr):
        return str(self.content) + formatstr

>>> m = MyPrintableObj("Something to print")
>>> '{: a fancy string}'.format(m)
'Something to print a fancy string'

【讨论】:

  • 在你的两个答案中选择一个并不容易。但是 +1 因为它也很有趣。 (解决此案的另一种方法,虽然这不是我想要做的,有什么可能但不是一个好主意)。
【解决方案2】:

内置的str 是type。当你执行str(custom_object) 之类的东西时,str 的构造函数会调用对象的__str__() 方法。你不能改变类型的签名而不覆盖它(这不是一个好主意)。

class _str(str):
    def __new__(cls, *args, **kwargs):
        if args:
            obj = args[0]
            if hasattr(obj, '__str__'):
                return obj.__str__(**kwargs)
        return str.__new__(cls, *args, **kwargs)
str = _str

是的,显然不是一个好主意,但这是用法:

class Example:
    def __str__(self, **kwargs):
        return 'kwargs: {}'.format(kwargs)

print str(Example(), arg1=1, arg2=2)
# kwargs: {'arg1': 1, 'arg2': 2}

在您的自定义对象上显式调用 __str__ 方法可能是一个更好的主意,尽管它是一个“dunder”方法。

【讨论】:

  • 好吧,我对__str__() 和builtin str() 感到困惑。我显然不想覆盖str(),做我想做的事需要什么。所以我不会,但感谢你展示了如何去做,尽管这是一个错误的想法。
  • @steffen 覆盖内置类型会使任何阅读代码的人(包括您未来的自己)感到困惑,并且可能难以跟踪哪些会导致意外结果
  • @JaredGoguon:毫无疑问,可读性很重要。但在我看来,如果我只添加功能,影响会很小,可读性也不会受到影响。
猜你喜欢
  • 1970-01-01
  • 2014-07-30
  • 2015-09-25
  • 1970-01-01
  • 2014-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多