Атрибуты экземпляра, сгенерированные из итерируемого с самим собой .__ setattr__.Есть ли способ лучше? - PullRequest
0 голосов
/ 18 июня 2019

Когда вы устанавливаете атрибуты для экземпляра из некоторого повторяемого объекта, подобного этому:

class DogWith100Legs():
    def __init__(self, legs_colors):
        for leg_i, color in legs_colors.items():
            self.__setattr__(leg_i, color)

legs_colors = {'leg_1': 'white', 'leg_2': 'brown', ... , 'leg_100': 
'black'}
doge = DogWith100Legs(legs_colors)
print(doge.leg_100)

, он работает нормально.Но PyCharm выделит leg_100 с предупреждением: «Неразрешенная ссылка« leg_100 »для класса« DogWith100Legs ».

Почему я хочу это сделать? Я хочу создать древовидный объект. Как и BeautifulSoup. Но bs4 делает».такой проблемы нет в PyCharm

Также есть комментарии в одинаковых вопросах (например, PyCharm предупреждает о неразрешенном атрибуте для атрибутов, генерируемых dict ), где люди говорят, что это плохая практика

Что будет хорошей практикой? Или, может быть, вы знаете хороший способ успокоить Pycharm? (Не отключая проверку Pycharm)

Ответы [ 3 ]

2 голосов
/ 18 июня 2019

PyCharm (и любая другая IDE) выдаст вам предупреждения / ошибки, потому что в __init__ вы должны объявлять каждого члена объекта.

Поскольку вы передаете диктовку, вероятно, лучше всего создать экземпляр диктата и в своем классе, а затем просто получить нужное значение с помощью ключа self.my_dict['leg_x'], а не self.leg_x.

class DogWith100Legs():
def __init__(self, legs_colors):
    self.legs_colors = legs_colors.copy()

legs_colors = {'leg_1': 'white', 'leg_2': 'brown', 'leg_100': 'black'}
doge = DogWith100Legs(legs_colors)
print(doge.legs_colors['leg_100'])
1 голос
/ 18 июня 2019

Зависит от предполагаемого использования.

1 Если вы собираетесь обращаться к данным напрямую по имени, и между элементами нет явной связи.

print(dog.leg_32)
print(dog.leg_5)

Только в этом случае __setattr__ отлично.

2 Вы планируете получать данные косвенно, и / или существует некоторая связь (например, предыдущая, следующая):

i = 25
print(dog.leg[i])
print(dog.leg[i+1])

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

0 голосов
/ 18 июня 2019

Я бы немного переосмыслил то, что вы пытаетесь сделать - возможно, даже посмотрите исходный код BeautifulSoup, чтобы увидеть, как они это делают.

В общем, нет никаких причин (о которых я могу думать) для динамического определения атрибутов экземпляра, подобных этому. У вас должен быть leg словарь или список в ваших Dog объектах, например:

def __init__(self, legs_colors: dict):
    self.legs_colors = legs_colors.copy()

Атрибуты экземпляра должны быть важны индивидуально, но я сомневаюсь, что вы планируете использовать leg_1 иначе, чем вы планируете использовать leg_72, тем более что вы не можете гарантировать, что любой из этих атрибутов будет существовать так, как вы определено __init__.

Кроме того, когда вы позже получите доступ к этим атрибутам ног, вы, вероятно, захотите сделать это динамически. В этом случае вам придется прибегнуть к чему-то вроде:

for leg in [f'leg_{i}' for i in range(100)]
    color = getattr(doge, leg)
    # do something with leg and color

вместо более простого, ясного и менее вонючего:

for leg, color in doge.legs_colors.items():
    # do something with leg and color

Вы по-прежнему можете программировать различные интерфейсы для доступа к своему словарю leg_colors, если хотите. Например, вы можете перезаписать __getitem__ в своем классе Dog, если хотите иметь возможность делать doge[i] напрямую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...