检查对象属性是否非空 Python

8

我可以这样检查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 如何评估像 listdict 这样的 标准数据类型 ,以根据它们包含的项目或为空来将其转换为 TrueFalse

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


尝试这样写:if obj1.lis1: print "yes" - rurp
5
可能是 Python 中布尔表达式的求值 的重复问题。 - TigerhawkT3
是的,我可以……但如果有很多属性……仍然可以通过编写 if obj1.attr1 and obj1.attr2 ……等等来实现……但我想避免这种情况……我更感兴趣的是了解 if 如何评估 Python 的标准数据类型…… - Anurag Sharma
7个回答

7
你需要实现__nonzero__方法(对于Python3是__bool__)。 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, ...))

答案是不正确的,因为问题本身也被错误地提出了。 - Alexander

3

使用内置的vars()函数,可以很方便地检查对象是否具有任何非空属性。结合__bool__方法,您可以得到以下代码:

def __nonzero__(self):
    return any(vars(self).values())

为什么要使用 list - notoria

2
在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

很想听听这个答案有什么问题/不好的地方,这是我改进答案的唯一途径。 - Anand S Kumar
2
这并不是不准确的,但有可能是因为那个投票者正在根据答案的实用性进行评估,并认为重复问题上的答案并不实用。 - TigerhawkT3

0
在Python中,如果您不声明属性,则无法知道要期望哪些属性。声明属性的标准方法在dataclass中提供。
请参见https://docs.python.org/3/library/dataclasses.html
from dataclasses import dataclass

@dataclass
class my_class:
   lis1:list = []
   dict1:dict = {}

   def isEmtpy(self)->bool:
      return len(self.lis1)+len(self.dict1)==0

为了实现更通用的解决方案,您可能需要检查https://github.com/python/cpython/blob/3.11/Lib/dataclasses.py上的dataclass源代码,特别是字段访问器

0
如果你的类定义了(在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)的副作用来获得布尔行为。


0

结合使用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')

这段代码片段预期不会打印任何内容。


0
根据许多答案和重复的投票建议,您需要覆盖__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__方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接