从这样的可迭代对象为实例设置属性时:
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检查)
答案 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])
在这种情况下,所有数据都应放入容器中(list
,dict
是最常见的)。这很可能就是您想要的。
答案 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]
。