Python 当属性不存在时,为什么getattr()会引发异常';不存在?
这件事让我困惑不解。考虑下面的Django模型-代表动物园管理员和负责清洁的动物园的笼子: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
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"