【问题标题】:Check if object attributes are non-empty python检查对象属性是否为非空python
【发布时间】:2015-09-29 05:29:23
【问题描述】:

我可以检查python列表或字典是否为空

lis1, dict1 = [], {}
# similar thing can be done for dict1
if lis1:
    # Do stuff
else:
    print "List is empty"

如果我尝试对我的类对象执行此操作,即通过键入 if my_object: 检查我的对象属性是否为非空,这始终评估为 True

>>> class my_class(object):
...   def __init__(self):
...     self.lis1 = []
...     self.dict1 = {}
... 
>>> obj1 = my_class()
>>> obj1
<__main__.my_class object at 0x10c793250>
>>> if obj1:
...   print "yes"
... 
yes

我可以专门编写一个函数来检查我的对象属性是否为非空,然后调用if obj1.is_attributes_empty():,但我更想知道if 如何评估standard data-types,如listdict TrueFalse 取决于它们包含的项目或为空的项目。

如果我想用我的类对象实现这个功能,我需要重写或更改哪些方法?

【问题讨论】:

  • 试试这个:if obj1.lis1: print "yes"
  • 是的,我可以....但是如果它们的属性很多.....仍然可以通过编写 if obj1.attr1 和 obj1.attr2 .... 等来实现。 ..但我想避免这种情况....我更感兴趣的是知道 if 如何评估 python 的标准数据类型 ....

标签: python if-statement


【解决方案1】:

您需要实现__nonzero__ 方法(或__bool__ 用于Python3)

https://docs.python.org/2/reference/datamodel.html#object.nonzero

class my_class(object):
    def __init__(self):
        self.lis1 = []
        self.dict1 = {}

    def __nonzero__(self):
        return bool(self.lis1 or self.dict1)

obj = my_class()
if obj:
    print "Available"
else:
    print "Not available"

Python 还会检查 __len__ 方法的真实性,但这对您的示例似乎没有意义。

如果你有很多属性需要检查,你可能更喜欢

return any((self.lis1, self.dict1, ...))

【讨论】:

    【解决方案2】:

    Truth value testing for Python 2.x的文档中给出-

    用户定义类的实例,如果该类定义了 __nonzero__()__len__() 方法,则该方法返回整数零或布尔值 False。

    对于Python 3.x -

    用户定义类的实例,如果该类定义了__bool__()__len__() 方法,则该方法返回整数零或布尔值False。

    根据你的类的定义,如果可能有意义定义__len__()方法,它返回列表长度的总和以及字典。然后会调用这个方法来确定是否将对象解释为TrueFalse 在布尔上下文中。示例 -

    class my_class(object):
        def __init__(self):
            self.lis1 = []
            self.dict1 = {}
        def __len__(self):
            print("In len")
            return len(self.lis1) + len(self.dict1)
    

    演示 -

    >>> class my_class(object):
    ...     def __init__(self):
    ...         self.lis1 = []
    ...         self.dict1 = {}
    ...     def __len__(self):
    ...         print("In len")
    ...         return len(self.lis1) + len(self.dict1)
    ...
    >>> obj = my_class()
    >>> if obj:
    ...     print("yes")
    ...
    In len
    >>> obj.lis1.append(1)
    >>>
    >>> if obj:
    ...     print("yes")
    ...
    In len
    yes
    

    【讨论】:

    • 很想听听这个答案有什么问题/不好,这是我可以改进答案的唯一方法。
    • 这不是不准确的,但有可能反对者正在根据有用性进行评估,并且认为重复问题的答案没有用。
    【解决方案3】:

    如果您的类定义了(在 Py2 上)__nonzero__、(在 Py3 上)__bool__ 或(在任一上)__len__,那么它将用于评估该类对象的“真实性”(如果只是__len__ 已定义,实例返回非零时为真,返回零时为假)。因此,例如,要让您的类简单地报告其属性在 Py2 或 Py3 中是否为非空,您需要添加:

     def __bool__(self):
         return bool(self.lis1 or self.dict1)
     __nonzero__ = __bool__ # To make it work on Py2 too
    

    或者,如果您的类实例具有有意义的长度,您可以定义:

     def __len__(self):
         return len(self.lis1) + len(self.dict1)  # For example; I doubt the length is meaningful in terms of both
    

    并通过支持len(myobject) 的副作用获得布尔行为。

    【讨论】:

      【解决方案4】:

      结合使用any()__bool__(self) 的答案,以下代码将允许您使用列表理解检查所有属性。

      class my_class(object):
          def __init__(self):
              self.list1 = []
              self.dict1 = {}
      
          def __bool__(self):
              check = any([self.__dict__[attr] for attr in self.__dict__.keys()])
      
              return check
      
      obj1 = my_class()
      
      if obj1:
          print('yes')
      

      此代码 sn-p 不会按预期打印任何内容。

      【讨论】:

        【解决方案5】:

        正如许多答案和重复投票所暗示的那样,您需要覆盖 __nonzero__ 方法。但是,根据您的评论,您还希望避免显式枚举属性。这可以通过这样的技巧来完成:

        class Example(object):
            def __init__(self):
                self._values = {}
                self.attr1 = []
                self.attr2 = {}
        
            def __setattr__(self, name, value):
                self.__dict__[name] = value
                if not name.startswith('_'):
                    self._values[name] = value  # keep track of the assigned attributes
        
            def __nonzero__(self):
                return any(self._values.itervalues())
        

        这会处理所有稍后分配或修改的公共属性:

        >>> ex = Example()
        >>> bool(ex)
        False
        >>> ex.attr1.append('data')
        >>> bool(ex)
        True
        >>> ex.attr1.pop()
        >>> ex.attr3 = 42
        bool(ex)
        >>> False
        

        属性删除处理不当,需要覆盖__delattr__

        【讨论】:

          猜你喜欢
          • 2014-08-22
          • 2020-09-21
          • 1970-01-01
          • 1970-01-01
          • 2011-09-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-06
          相关资源
          最近更新 更多