[英]Instance attributes, generated from iterable with self.__setattr__. Is there a better way?
When you setting attributes to an instance from some iterable like this: 当您从一些可迭代的实例中为实例设置属性时:
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)
it works fine. 它工作正常。 But PyCharm will highlight leg_100 with a warning: "Unresolved reference 'leg_100' for class 'DogWith100Legs'. 但是PyCharm会突出显示leg_100并显示警告:“类'DogWith100Legs'的未解析引用'leg_100'。
Why i want to do this? 为什么我要这样做? I want to create tree-like object. 我想创建树状对象。 Like BeautifulSoup do. 就像BeautifulSoup一样。 But bs4 does not have such a problem in PyCharm 但是bs4在PyCharm中没有这样的问题
Also, there are comments in similar questions (like PyCharm warns about unresolved attribute for dict generated attributes ), where people say, that it is a bad practice 另外,在类似的问题中也有评论(例如PyCharm警告dict生成的属性有未解决的属性 ),人们说这是一种不良做法
What will be a good practice? 有什么好的做法? Or may be you know a good way to calm down Pycharm? 也许您知道平息Pycharm的好方法吗? (Not disabling Pycharm check) (不禁用Pycharm检查)
PyCharm (and every other IDE) will give you warnings/errors because in __init__
you have to declare every member of the object. PyCharm(以及所有其他IDE)将给您警告/错误,因为在__init__
您必须声明该对象的每个成员。
Because you are passing a dict, probably the best thing to do is to instantiate a dict into your class too, and then just get the value you need with the key self.my_dict['leg_x']
and not self.leg_x
. 因为您要传递一个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'])
It depends on intended usage. 这取决于预期用途。
1 If you are going to access the data directly by name, and there is no obvious relationship between items. 1如果您要直接通过名称访问数据,并且项目之间没有明显的关系。
print(dog.leg_32)
print(dog.leg_5)
Only in this case is __setattr__
fine. 仅在这种情况下__setattr__
可以。
2 You plan to retrieve the data indirectly, and/or there is some relationship (eg previous, next): 2您计划间接检索数据,并且/或者存在某种关系(例如,上一个,下一个):
i = 25
print(dog.leg[i])
print(dog.leg[i+1])
In this case all data should be placed into a container ( list
, dict
are the most common ones). 在这种情况下,所有数据都应放入容器中( list
, dict
是最常见的数据)。 Most probably this is what you want. 这很可能就是您想要的。
I would rethink what you are trying to do a little bit - maybe even check out the BeautifulSoup source code to see how they do it. 我会重新考虑您要尝试做些什么-甚至可以查看BeautifulSoup源代码以了解他们是如何做到的。
In general though, there is no reason (that I can think of) to dynamically define instance attributes like this. 但总的来说,没有理由(我能想到)动态定义这样的实例属性。 You should simply have a leg
dictionary or list within your Dog
objects, like so: 您应该只在Dog
对象中包含一个leg
字典或列表,如下所示:
def __init__(self, legs_colors: dict):
self.legs_colors = legs_colors.copy()
Instance attributes should be individually important, but I doubt that you plan to use leg_1
differently than you plan to use leg_72
, especially since you can't guarantee that either of these attributes will exist with the way you have defined __init__
. 实例属性应该是个别重要的,但我怀疑你计划使用leg_1
比你计划使用不同leg_72
,特别是因为你不能保证这两种属性将与您所定义的方式存在__init__
。
Also, when you later access these leg attributes, you will likely want to do so dynamically. 另外,当您以后访问这些支腿属性时,您可能希望动态地进行操作。 In which case you would have to resort to something like: 在这种情况下,您将不得不诉诸以下内容:
for leg in [f'leg_{i}' for i in range(100)]
color = getattr(doge, leg)
# do something with leg and color
instead of the simpler, clearer, and less smelly: 而不是更简单,更清晰,更不臭:
for leg, color in doge.legs_colors.items():
# do something with leg and color
You can still program different interfaces for accessing your legs_colors dictionary, if you'd like to. 如果愿意,您仍然可以编写其他接口来访问legs_colors字典。 For example, you could overwrite __getitem__
on your Dog class if you want to be able to do doge[i]
directly. 例如,如果您想直接执行doge[i]
,则可以在Dog类上覆盖__getitem__
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.