Python 当属性不存在时,为什么getattr()会引发异常';不存在?

Python 当属性不存在时,为什么getattr()会引发异常';不存在?,python,django,django-models,getattr,Python,Django,Django Models,Getattr,这件事让我困惑不解。考虑下面的Django模型-代表动物园管理员和负责清洁的动物园的笼子: class Zookeeper(moodels.Model): name = models.CharField(max_length=40) class Cage(models.Model): zookeeper = models.ForeignKey(Zookeeper) 现在假设我想将一个接收器连接到Cage的post_init信号: @receiver(models.signal

这件事让我困惑不解。考虑下面的Django模型-代表动物园管理员和负责清洁的动物园的笼子:

class Zookeeper(moodels.Model):
    name = models.CharField(max_length=40)

class Cage(models.Model):
    zookeeper = models.ForeignKey(Zookeeper)
现在假设我想将一个接收器连接到
Cage
post_init
信号:

@receiver(models.signals.post_init, sender=Cage)
def on_cage_init(instance, **kwargs):
    print instance.zookeeper
正如所料,这会引发一个异常,因为尚未将
笼子
分配给
动物园管理员
。考虑下面对接收器主体的修改:

print getattr(instance, 'zookeeper', 'No Zookeeper')
由于没有为实例分配一个Zookeeper,因此可能会打印“No Zookeeper”。相反,会引发一个异常:

Traceback (most recent call last):
  File "../zoo/models.py", line 185, in on_cage_init
    print getattr(instance, 'zookeeper', 'No Zookeeper')
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/fields/related.py", line 324, in __get__
    "%s has no %s." % (self.field.model.__name__, self.field.name))
DoesNotExist: Cage has no zookeeper.
为什么它会引发一个例外?如果属性不存在,
getattr()
不应该返回提供的默认值吗?我可以证明该属性不存在于:

print hasattr(instance, 'zookeeper')

…打印
False

的类很可能已定义了
\uuu getattribute\uuu
。请参见此示例:

>>> class O(object):
...     def __getattribute__(self, name):
...         raise Exception("can't get attribute")
...
>>> o = O()
>>> getattr(o, 'test', 'nothing')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __getattribute__
Exception: can't get attribute
因此,这可能被认为是
DoesNotExist
异常定义中的一个缺陷,它没有正确地继承
AttributeError

一个更完整的示例演示上述所有内容:

>>> class O(object):
...     def __getattribute__(self, name):
...         if name == 'test':
...             return 'good value'
...         elif name == 'bad':
...             raise Exception("don't raise this")
...         else:
...             raise DoesNotExist()
...
>>> class DoesNotExist(AttributeError):
...     pass
...
>>> o = O()
>>> getattr(o, 'test', 'nothing')
'good value'
>>> getattr(o, 'something', 'nothing')
'nothing'
>>> getattr(o, 'bad', 'nothing')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __getattribute__
Exception: don't raise this

@metatoaster的解释真的很好,这基本上就是正在发生的事情。请参见
\uuuu获取\uuuuu
定义的魔法方法

作为一个解决方案,我将应用这个原则。尝试获取属性并捕获特定异常:

from django.core.exceptions import ObjectDoesNotExist

try:
    print instance.zookeeper
except ObjectDoesNotExist:
    print "No zookeeper"

+1良好的解释±0可怕的命名(
o
o
O0
oO
oO
);)@msw我发誓,
O
C
两个键都紧挨着!您还可以通过捕获
Zookeeper.DoesNotExist
来避免导入
ObjectDoesNotExist
def safe_getattr(obj, name, default):
    try:
        return getattr(obj, name, default)
    except Exception:  # or your specific exceptions
        return default
from django.core.exceptions import ObjectDoesNotExist

try:
    print instance.zookeeper
except ObjectDoesNotExist:
    print "No zookeeper"