Using __str__ representation for printing objects in containers in Python

前端 未结 3 803
后悔当初
后悔当初 2021-01-04 18:06

I\'ve noticed that when an instance with an overloaded __str__ method is passed to the print function as an argument, it prints as intended. Howeve

3条回答
  •  囚心锁ツ
    2021-01-04 18:39

    I'm not sure why exactly the __str__ method of a list returns the __repr__ of the objects contained within - so I looked it up: [Python-3000] PEP: str(container) should call str(item), not repr(item)

    Arguments for it:

    -- containers refuse to guess what the user wants to see on str(container) - surroundings, delimiters, and so on;

    -- repr(item) usually displays type information - apostrophes around strings, class names, etc.

    So it's more clear about what exactly is in the list (since the object's string representation could have commas, etc.). The behavior is not going away, per Guido "BDFL" van Rossum:

    Let me just save everyone a lot of time and say that I'm opposed to this change, and that I believe that it would cause way too much disturbance to be accepted this close to beta.


    Now, there are two ways to resolve this issue for your code.

    The first is to subclass list and implement your own __str__ method.

    class StrList(list):
        def __str__(self):
            string = "["
            for index, item in enumerate(self):
                string += str(item)
                if index != len(self)-1:
                    string += ", "
            return string + "]"
    
    class myClass(object):
        def __str__(self):
            return "myClass"
    
        def __repr__(self):
            return object.__repr__(self)
    

    And now to test it:

    >>> objects = [myClass() for _ in xrange(10)]
    >>> print objects
    [<__main__.myClass object at 0x02880DB0>, #...
    >>> objects = StrList(objects)
    >>> print objects
    [myClass, myClass, myClass #...
    >>> import random
    >>> sample = random.sample(objects, 4)
    >>> print sample
    [<__main__.myClass object at 0x02880F10>, ...
    

    I personally think this is a terrible idea. Some functions - such as random.sample, as demonstrated - actually return list objects - even if you sub-classed lists. So if you take this route there may be a lot of result = strList(function(mylist)) calls, which could be inefficient. It's also a bad idea because then you'll probably have half of your code using regular list objects since you don't print them and the other half using strList objects, which can lead to your code getting messier and more confusing. Still, the option is there, and this is the only way to get the print function (or statement, for 2.x) to behave the way you want it to.

    The other solution is just to write your own function strList() which returns the string the way you want it:

    def strList(theList):
        string = "["
        for index, item in enumerate(theList):
            string += str(item)
            if index != len(theList)-1:
                string += ", "
        return string + "]"
    
    >>> mylist = [myClass() for _ in xrange(10)]
    >>> print strList(mylist)
    [myClass, myClass, myClass #...
    

    Both solutions require that you refactor existing code, unfortunately - but the behavior of str(container) is here to stay.

提交回复
热议问题