【问题标题】:Creating __repr__ to print subclass data创建 __repr__ 以打印子类数据
【发布时间】:2020-05-14 12:35:45
【问题描述】:

我想创建一个基类,它具有所有子级都继承的属性,并且还有一个描述性的__repr__ 方法。以下似乎是可接受的实现方式吗?

from collections import Counter

class Component:
    cnt = Counter()
    def __init__(self, _type, **kwargs):
        Component.cnt[_type] += 1
        self.type = _type
        self.identifier = f'{self.type[0]}{Component.cnt[_type]}'
        self._kwargs = kwargs
    def __repr__(self):
        s = f'{self.__class__.__name__}('
        for k, v in self._kwargs.items():
            s += f'{k}={v!r}, '
        s = s.strip(', ') + f') # identifier: {self.identifier}'
        return s

class Battery(Component):
    # outbound is positive terminal
    def __init__(self, voltage):
        super().__init__(self.__class__.__name__, voltage=voltage)
        self.voltage = voltage

>>> b=Battery(9)
>>> b
Battery(voltage=9) # identifier: B1

具体来说,self._kwargs 看起来像黑客吗?有什么更好的方法可以做到这一点?或者,有没有比我现在做的更好、更 Python 的方法?

【问题讨论】:

    标签: python python-3.x repr


    【解决方案1】:

    不必将self.__class__.__name__ 传递给super().__init__ - 超类的__init__ 方法可以直接访问它,就像您的__repr__ 方法一样。所以self.type 属性是多余的。

    这是在基类中编写__repr__ 的合理方法:可以使用对象自己的__dict__,而不是使用自己的_kwargs 属性。这包括identifier 属性,因此您无需单独添加。

    from collections import Counter
    
    class Component:
        cnt = Counter()
        def __init__(self, **kwargs):
            _type = self.__class__.__name__
            Component.cnt[_type] += 1
            self.identifier = _type[0] + str(Component.cnt[_type])
            super().__init__(**kwargs) # co-operative subclassing
        def __repr__(self):
            return '{0}({1})'.format(
                self.__class__.__name__,
                ', '.join(
                    '{0}={1!r}'.format(k, v)
                    for k, v in self.__dict__.items()))
    
    class Battery(Component):
        # outbound is positive terminal
        def __init__(self, *, voltage, **kwargs):
            self.voltage = voltage
            super().__init__(**kwargs) # co-operative subclassing
    

    例子:

    >>> b = Battery(voltage=9) # keyword-only argument for co-operative subclassing
    >>> b
    Battery(voltage=9, identifier='B1')
    

    我已经用 cmets 标记了一些关于 co-operative subclassing 的代码。在类层次结构中,每个__init__ 方法都可以将其参数作为关键字,并将其**kwargs 传递给super().__init__ 方法,这样您就不必在两个类中多次编写相同的参数名称。

    如果您使用多重继承,调用super().__init__ even from your base class 也很重要。即使您不使用多重继承,这也会调用object.__init__,它的简洁效果是确保没有其他__init__ 方法未处理的“未使用”参数。

    【讨论】:

    • 很棒的答案,这非常有帮助。非常感谢!
    • 一个问题。为什么def __init__(self, *, voltage, **kwargs): 中有额外的*
    • 这使得voltage 成为仅关键字参数,因此它与仅通过kwargs 将其作为关键字参数的子类一致。这不是真的必要;没有它,代码也能正常工作。
    猜你喜欢
    • 2019-04-05
    • 1970-01-01
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 2013-01-20
    • 2012-05-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多