Метод __str__, перебирающий атрибуты класса - PullRequest
0 голосов
/ 17 мая 2019

У меня есть класс с атрибутами из нескольких списков (сегодня 8, но он наверняка будет расти, потому что мой код опирается на предыдущий код, который использовался в prod в другом проекте)

В этом классе есть функция __str__ для красивой печати информации списка. Сегодня функция отображает информацию о каждом списке, но вызывает их именно, а мне это не нравится, потому что каждый раз, когда меняются атрибуты класса (добавление / удаление списка), мне приходится обновлять этот метод

Я ищу способ динамически перебирать атрибуты моего класса для отображения информации

В качестве примера давайте представим класс ниже

class shopping_cart:
    def __init__(self):
        self.fruits = []
        self.vegetables = []
        self.meat = []
        self.bread = []

    def __str__(self):
        msg = ""
        msg += "shopping cart content\n"
        msg += "---------------------\n"
        msg += "---fruits-----------: " + len(self.fruits) +"\n
        msg += "---vegetables-------: " + len(self.vegetables) +"\n
        msg += "---meat-------------: " + len(self.meat) +"\n
        msg += "---bread------------: " + len(self.bread) +"\n
        return msg

Как видите, стоимость обслуживания высока. Я ищу что-то более динамичное, что будет больше похоже на

class shopping_cart:
    def __init__(self):
        self.fruits = []
        self.vegetables = []
        self.meat = []
        self.bread = []

    def __str__(self):
        msg = ""
        msg += "shopping cart content\n"
        msg += "---------------------\n"
        for item in <list of my class attributes>:
            msg += "---" + item +"-----------: " + len(item) +"\n
        return msg

Легко читается и прост в обслуживании.

Ответы [ 3 ]

1 голос
/ 17 мая 2019

Вы можете сделать это несколькими способами:

1 - используйте атрибут __dict__ вашего класса. Это дает вам словарь объекта всех переменных, и вы можете перебирать их

s = shopping_cart()
s.__dict__

это должно вывести что-то вроде

{'fruits':[], 'vegetables':[], ... }

2 - Вы можете использовать словарь списков вместо набора списков и выполнять итерацию по словарю.

3 - Вы также можете использовать список списков (например, [self.fruits, self.vegetables ...] и выполнять итерации по этому.

1 голос
/ 17 мая 2019

Вы можете использовать встроенную функцию vars() для экземпляра класса (не самого class):

class ShoppingCart:
    def __init__(self):
        self.fruits = []
        self.vegetables = []
        self.meat = []
        self.bread = []

    def __str__(self):
        msg  = "shopping cart contents\n"
        msg += "----------------------\n"
        for attrname in vars(self):
            value = getattr(self, attrname)
            if isinstance(value, list):
                msg += "---{}{}: {:2}\n".format(
                            attrname, '-'*(15-len(attrname)), len(value))
        return msg


cart = ShoppingCart()
print(cart)

Выход:

shopping cart contents
----------------------
---fruits---------:  0
---vegetables-----:  0
---meat-----------:  0
---bread----------:  0
1 голос
/ 17 мая 2019

Я думаю, вам нужна только одна функция: dir и getattr. Вот пример

class shopping_cart:
    def __init__(self):
        self.fruits = []
        self.vegetables = []
        self.meat = []
        self.bread = []

    def __str__(self):
        msg = ""
        msg += "shopping cart content\n"
        msg += "---------------------\n"
        members = [attr for attr in dir(self) if not callable(getattr(self, attr)) and not attr.startswith("__")]
        for item in members:
            msg += "---" + item +"-----------: " + str(getattr(self,item) )+"\n"
        return msg
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...