通过self .__ setattr__进行迭代生成的实例属性。有更好的方法吗?

时间:2019-06-18 16:07:09

标签: python pycharm

从这样的可迭代对象为实例设置属性时:

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并显示警告:“类'DogWith100Legs'的未解析引用'leg_100'。

为什么我要这样做?我想创建树状对象。就像BeautifulSoup一样。但是bs4在PyCharm中没有这样的问题

此外,在类似的问题中也有评论(例如PyCharm warns about unresolved attribute for dict generated attributes),人们会说这是一种不好的做法

什么是好习惯?也许您知道平息Pycharm的好方法吗? (不禁用Pycharm检查)

3 个答案:

答案 0 :(得分:2)

PyCharm(以及所有其他IDE)将向您发出警告/错误,因为在__init__中,您必须声明该对象的每个成员。

因为要传递一个dict,所以最好的办法就是也将dict实例化到您的类中,然后仅使用键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 :(得分:1)

这取决于预期用途。

1如果您要直接通过名称访问数据,并且项目之间没有明显的关系。

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

在这种情况下,只能使用__setattr__

2您打算间接检索数据,并且/或者存在某种关系(例如,上一个,下一个):

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

在这种情况下,所有数据都应放入容器中(listdict是最常见的)。这很可能就是您想要的。

答案 2 :(得分:0)

我会重新考虑您要尝试做些什么-甚至可以查看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

如果愿意,您仍然可以编写其他接口来访问legs_colors字典。例如,如果您想直接执行__getitem__,则可以在Dog类中覆盖doge[i]