【问题标题】:Instance attributes, generated from iterable with self.__setattr__. Is there a better way?实例属性,通过 self.__setattr__ 迭代生成。有没有更好的办法?
【发布时间】:2019-11-01 08:02:51
【问题描述】:

当您从这样的一些可迭代对象中为实例设置属性时:

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中没有这样的问题

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

什么是好的做法?或者您是否知道让 Pycharm 平静下来的好方法? (不禁用 Pycharm 检查)

【问题讨论】:

  • 如果您有动态属性,您应该将它们存储在字典中。另一方面,腿可以是一个列表。

标签: python pycharm


【解决方案1】:

我会重新考虑一下您正在尝试做的事情 - 甚至可以查看 BeautifulSoup 源代码,看看他们是如何做到的。

但总的来说,没有理由(我能想到的)像这样动态定义实例属性。您应该在您的 Dog 对象中简单地拥有一个 leg 字典或列表,如下所示:

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 字典。例如,如果您希望能够直接执行 doge[i],则可以在 Dog 类上覆盖 __getitem__

【讨论】:

    【解决方案2】:

    这取决于预期用途。

    1如果你是直接通过名字来访问数据,并且item之间没有明显的关系。

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

    只有在这种情况下__setattr__ 才可以。

    2 您计划间接检索数据,和/或存在某种关系(例如,上一个、下一个):

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

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

    【讨论】:

      【解决方案3】:

      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'])
      

      【讨论】:

        猜你喜欢
        • 2021-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-21
        • 2015-08-27
        • 1970-01-01
        相关资源
        最近更新 更多