【问题标题】:Avoid Pylint warning E1101: 'Instance of .. has no .. member' for class with dynamic attributes避免 Pylint 警告 E1101:具有动态属性的类的“.. 实例没有 .. 成员”
【发布时间】:2016-06-29 15:43:24
【问题描述】:

想象一个函数,它动态地 使用setattr 向对象添加属性。这样做的原因是我想将一些外部结构(例如给定的参数树)映射到一个对象:

my_object = SomeClass()
apply_structure(my_object, some_descriptor)
my_object.device1.enabled = True

从技术上讲,这是可行的,但 Pylint 当然正确地抱怨 'device1' 不是SomeClass 的成员。

我可以禁用警告,但这会很糟糕(因为在所有情况下,当属性由于拼写错误等原因不存在时,我仍然希望得到警告)。

是否有一种常见且合法的(Pylint-proof)方法可以动态地将成员添加到不会导致警告的对象?

或者:我可以只为一个对象而不是一个行/块/文件禁用Pylint吗?

解释

您可能想知道,当我计划稍后以硬编码的方式访问这些属性时,为什么要动态地为对象配备成员属性。

原因是:我有一个程序的动态部分(装饰发生的地方)和一个静态部分,它专门用于某个场景。所以我可以也为这个场景创建一个静态类,但在很多情况下这会是多余的。

以下专用代码可能允许访问可能连接到某些总线的设备的某些参数:

class MyDeviceHandler:
   on_get_some_subtree_element(self):
      return _some_internal_value
   on_set_some_subtree_element(self, value):
      _some_internal_value = value

dev = MyDeviceHandler()

decorate_object_with_device_structure(dev, 'some/attached/device')

dev.some.subtree.element = 5       <--- will call the set-callback
x = dev.some.subtree.element       <--- will call the get-callback

所以'some/attached/device' 背后的结构可能是任意的并且非常复杂,我不想在类结构中重现它。

消除此警告的一种方法是创建/访问基于dict 的树:

dev['some']['subtree']['element'] = 5

但这更难写,也不好读——我这样做只是为了让 Pylint 安静。

【问题讨论】:

  • 我的问题是,如果您事先知道要访问的结构,为什么不首先明确定义该结构?
  • 这正是问题所在。我不知道。实际上,我从设备属性树(可以是任何东西)中读取了一个结构,然后构建了一个 Python 对象。我将在问题中进一步详细说明..
  • 您可以设置generated-membersignored-classes options for pylint(在命令行上,或在[TYPECHECK].pylintrc
  • @TheCompiler 您应该将其添加为答案。 generated-members 是我用例的解决方案。我有一个 options 单例,多个模块会向其中添加选项(和默认值)。选项单例封装了与解析命令行选项相关的行为。但是选项的名称和默认值仍然根据使用这些特定选项的模块进行组织。
  • --generated-members=MyEnum 将错误静音Instance of 'str' has no 'value' memberpylint(no-member)

标签: python dynamic pylint


【解决方案1】:

只是为了提供现在对我有用的答案 - 正如The Compiler 建议的那样,您可以在您的项目.pylintrc 中为有问题的类添加规则:

[TYPECHECK]
ignored-classes=Fysom,MyClass

【讨论】:

  • 除非你添加 str 否则不起作用......这似乎坏了
  • 这更像是一个 hack 而非真正的解决方案,因为它忽略了问题而不是解决它,但我想它有效
【解决方案2】:

This page 描述了错误并提供了一种直接在代码中解决它的简单方法。 tl;博士

在为不存在的成员访问对象(变量、函数……)时使用。

误报:此消息可能会报告动态创建但在访问它们时存在的对象成员。

一位评论员提到可以在文件顶部的一行中使用# pylint: disable=no-member 禁用它。我还发现你可以在this reddit entry的基础上使用# pylint: disable=E1101

【讨论】:

  • 简洁全面的解决方案。这应该是公认的答案
  • 我认为这不是一个理想的解决方案,因为您将禁用对文件中所有代码的检查。这是一个有价值的检查,可以发现很多实际问题。您需要对使用该类的每个文件执行此操作。理想的解决方案是 pylint 仅忽略一个类的错误。
  • 您可以将其添加到错误所在行的末尾,以便仅禁用该行中的错误。这样您就不必为其余代码禁用它
【解决方案3】:

PyLint 在两种情况下都给出了这种类型的错误Link

  • 在访问对象(变量、函数……)时使用 不存在的成员。

  • 误报:此消息可能报告对象成员 动态创建,但在访问时存在。

由于此错误被识别为 E1101 错误。您可以通过在代码中添加以下行来解决此问题。

# pylint: disable=E1101

【讨论】:

    【解决方案4】:

    我可以通过将__getattr__ 方法添加到我的类中来避免此警告,当在对象上找不到属性时python 会调用该方法。虽然绝对不是最干净的解决方案,但它适用于我的特定用例,因为 pylint 认为该对象有效。

    import warnings
    class AppConfiguration(object):     
        ... 
        def __getattr__(self, name):
            ''' will only get called for undefined attributes '''
            warnings.warn('No member "%s" contained in settings config.' % name)
            return ''
    

    更多关于__getattr__方法的信息可以是found here

    【讨论】:

      【解决方案5】:

      试试这个!我的问题解决了!

      Pylint 不理解 Django 的动态字段。因此,我们需要向 Pylint 教授 Django 是什么

      *适用于 Windows 10 中的 vscode *

      $ pip install pylint-django
      $ cd your_project_folder
      $ code . // run vscode  
      

      在 vscode 中安装 Python 扩展、Django Snippets、Django 模板

      在vscode中打开.vscode/settings.json并添加:

      {
         "python.linting.pylintEnabled": true,
         "python.linting.enabled": true,
         "python.pythonPath": "venv\\Scripts\\python.exe",
         "python.linting.pylintArgs": [
             "--load-plugins",
             "pylint_django"
         ],
      }
      

      【讨论】:

      • 你为什么要把这个和 Django 联系起来?
      • 只添加 "python.linting.pylintArgs":[ " --load-plugins"] 对我来说就足够了。这似乎与 django 无关,因此被否决了。
      【解决方案6】:

      犹豫是否要添加到此答案中,因为如果有明确的方法可以使用 pylint 执行此操作,我更愿意。但是有一个正在运行的解决方案(至少从 pylint 2.7.4 开始)。在这个示例代码中,我使用“getattr”空操作来防止 pylint 认为它知道关于该对象的任何信息。显然,这种简单的事情可能无法继续向前发展,但我喜欢这样一个事实,即您可以控制您希望 pylint 忽略的确切内容,而无需触及源文件以外的任何内容,也无需在整个源文件中全局禁用检查.

      class MyClass():
          """an empty class"""
      
      myc = MyClass()
      print(myc.hello_world)  # pylint no-member
      myc = globals()['myc']
      print(myc.hello_world)  # no error flagged
      
      class MyDeviceHolder1():
          """a device holder class"""
          def __init__(self):
              self.devices = MyClass()
      
      mdh1 = MyDeviceHolder1()
      print(mdh1.devices.hello_world)  # pylint no-member
      
      class MyDeviceHolder2():
          """a device holder class"""
          def __init__(self):
              self.devices = MyClass()
              self.devices = getattr(self, 'devices')
      
      mdh2 = MyDeviceHolder2()
      print(mdh2.devices.hello_world)  # no error flagged
      print(mdh2.devixes.hello_world)  # pylint no-member
      

      【讨论】:

        【解决方案7】:

        获取no-member 的另一个可能原因是,缺少此类的__init_() 方法的self 参数:

        错误:

        class foo:
            def __init__(bar):
                self.bar = bar
        

        对:

        class foo:
            def __init__(self, bar):
                self.bar = bar
        

        获取no-member警告的应用代码:

        x = foo('bar')
        print(x.bar) # <-- this line will be the reported error line
        

        【讨论】:

          【解决方案8】:

          对我来说,安装 pylint-django 解决了这个问题:

          pip install pylint-django
          

          【讨论】:

          • 为什么要混合到 django?
          猜你喜欢
          • 1970-01-01
          • 2019-05-30
          • 1970-01-01
          • 1970-01-01
          • 2014-09-10
          • 2017-09-02
          • 2021-05-24
          • 1970-01-01
          • 2019-11-22
          相关资源
          最近更新 更多