Auto __repr__ method

前端 未结 6 775
囚心锁ツ
囚心锁ツ 2020-12-30 00:30

I want to have simple representation of any class, like { property = value }, is there auto __repr__?

相关标签:
6条回答
  • 2020-12-30 00:58

    Yes, you can make a class "AutoRepr" and let all other classes extend it:

    >>> class AutoRepr(object):
    ...     def __repr__(self):
    ...         items = ("%s = %r" % (k, v) for k, v in self.__dict__.items())
    ...         return "<%s: {%s}>" % (self.__class__.__name__, ', '.join(items))
    ... 
    >>> class AnyOtherClass(AutoRepr):
    ...     def __init__(self):
    ...         self.foo = 'foo'
    ...         self.bar = 'bar'
    ...
    >>> repr(AnyOtherClass())
    "<AnyOtherClass: {foo = 'foo', bar = 'bar'}>"
    

    Note that the above code will not act nicely on data structures that (either directly or indirectly) reference themselves. As an alternative, you can define a function that works on any type:

    >>> def autoRepr(obj):
    ...     try:
    ...         items = ("%s = %r" % (k, v) for k, v in obj.__dict__.items())
    ...         return "<%s: {%s}." % (obj.__class__.__name__, ', '.join(items))
    ...     except AttributeError:
    ...         return repr(obj)
    ... 
    >>> class AnyOtherClass(object):
    ...     def __init__(self):
    ...         self.foo = 'foo'
    ...         self.bar = 'bar'
    ...
    >>> autoRepr(AnyOtherClass())
    "<AnyOtherClass: {foo = 'foo', bar = 'bar'}>"
    >>> autoRepr(7)
    '7'
    >>> autoRepr(None)
    'None'
    

    Note that the above function is not defined recursively, on purpose, for the reason mentioned earlier.

    0 讨论(0)
  • 2020-12-30 00:59

    Well, I played a little bit with other answers and got a very pretty solution:

    class data:
        @staticmethod
        def repr(obj):
            items = []
            for prop, value in obj.__dict__.items():
                try:
                    item = "%s = %r" % (prop, value)
                    assert len(item) < 20
                except:
                    item = "%s: <%s>" % (prop, value.__class__.__name__)
                items.append(item)
    
            return "%s(%s)" % (obj.__class__.__name__, ', '.join(items))
    
        def __init__(self, cls):
            cls.__repr__ = data.repr
            self.cls = cls
    
        def __call__(self, *args, **kwargs):
            return self.cls(*args, **kwargs)
    

    You use it as a decorator:

    @data
    class PythonBean:
        def __init__(self):
            self.int = 1
            self.list = [5, 6, 7]
            self.str = "hello"
            self.obj = SomeOtherClass()
    

    and get a smart __repr__ out of the box:

    PythonBean(int = 1, obj: <SomeOtherClass>, list = [5, 6, 7], str = 'hello')
    

    This works with any recursive classes, including tree structures. If you try to put a self-reference in the class self.ref = self, the function will try (successfully) to work it out for about a second.

    Of course, always mind your boss - mine would not like such a syntax sugar ))

    0 讨论(0)
  • 2020-12-30 01:02

    Do you mean

    __dict__
    

    ?

    0 讨论(0)
  • 2020-12-30 01:03
    class MyClass:
        def __init__(self, foo: str, bar: int):
            self.foo = foo
            self.bar = bar
            self._baz: bool = True
    
        def __repr__(self):
            f"{self.__class__.__name__}({', '.join([f'{k}={v}' for k, v in self.__dict__.items() if not k.startswith('_')])})"
    
    mc = MyClass('a', 99)
    
    print(mc)
    # MyClass(foo=a, bar=99)
    # ^^^ Note that _baz=True was hidden here
    
    0 讨论(0)
  • 2020-12-30 01:03

    I use this helper function to generate repr s for my classes. It is easy to run in a unittest function, ie.

    def test_makeRepr(self):
        makeRepr(Foo, Foo(), "anOptional space delimitedString ToProvideCustom Fields")
    

    this should output a number of potential repr to the console, that you can then copy/paste into your class.

    def makeRepr(classObj, instance = None, customFields = None):
        """Code writing helper function that will generate a __repr__ function that can be copy/pasted into a class definition.
    
        Args:
            classObj (class):
            instance (class):
            customFields (string):
    
        Returns:
            None:
    
        Always call the __repr__ function afterwards to ensure expected output.
        ie. print(foo)
    
        def __repr__(self):
            msg = "<Foo(var1 = {}, var2 = {})>"
            attributes = [self.var1, self.var2]
            return msg.format(*attributes)
        """ 
        if isinstance(instance, classObj):
            className = instance.__class__.__name__
        else:
            className=classObj.__name__
    
        print('Generating a __repr__ function for: ', className,"\n")
        print("\tClass Type: "+classObj.__name__, "has the following fields:")
        print("\t"+" ".join(classObj.__dict__.keys()),"\n")
        if instance:
            print("\tInstance of: "+instance.__class__.__name__, "has the following fields:")
            print("\t"+" ".join(instance.__dict__.keys()),"\n")
        else:
            print('\tInstance of: Instance not provided.\n')
    
        if customFields:
            print("\t"+"These fields were provided to makeRepr:")
            print("\t"+customFields,"\n")
        else:
            print("\t"+"These fields were provided to makeRepr: None\n")
        print("Edit the list of fields, and rerun makeRepr with the new list if necessary.\n\n")
    
        print("repr with class type:\n")
        classResult = buildRepr( classObj.__name__, " ".join(classObj.__dict__.keys()))
        print(classResult,"\n\n")
    
        if isinstance(instance, classObj):
            instanceResult = buildRepr( instance.__class__.__name__, " ".join(instance.__dict__.keys()))
        else:
            instanceResult = "\t-----Instance not provided."
        print("repr with instance of class:\n")
        print(instanceResult,"\n\n") 
    
        if customFields:
            customResult = buildRepr( classObj.__name__, customFields)
        else:
            customResult = '\t-----Custom fields not provided'
        print("repr with custom fields and class name:\n")
        print(customResult,"\n\n")    
    
        print('Current __repr__')
        print("Class Object: ",classObj)
        if instance:
            print("Instance: ",instance.__repr__())
        else:
            print("Instance: ", "None")
    
    
    def buildRepr(typeName,fields):
        funcDefLine = "def __repr__(self):"
        msgLineBase  = '    msg = "<{typename}({attribute})>"'
        attributeListLineBase = '    attributes = [{attributeList}]'
        returnLine = '    return msg.format(*attributes)'
        x = ['self.' + x for x in fields.split()]
        xResult = ", ".join(x)
        y = [x + ' = {}' for x in fields.split()]
        yResult = ', '.join(y)
        msgLine = msgLineBase.format(typename = typeName, attribute = yResult)
        attributeListLine = attributeListLineBase.format(attributeList = xResult) 
        result = "{declaration}\n{message}\n{attributes}\n{returnLine}".format(declaration = funcDefLine,
                                                                           message = msgLine,
                                                                           attributes = attributeListLine,
                                                                           returnLine =returnLine )
        return result
    
    0 讨论(0)
  • 2020-12-30 01:16

    Simplest way:

    def __repr__(self):
        return str(self.__dict__)
    
    0 讨论(0)
提交回复
热议问题