如何在if语句中处理python异常

时间:2014-01-24 16:01:40

标签: python django if-statement exception-handling

例如,我收到了if声明:

if user.address.streetname == 'Target':
    pass
elif:
    (...)
else:
    (...)

但并非所有用户都有足够的资金来获得地址,因此可能会引发异常 在我的例子中,django DoesNotExist例外。在这种情况下,它应该假设为假。

如果elif else流动,如何在这个地方处理异常而不破坏?

4 个答案:

答案 0 :(得分:3)

如果user.address是模型实例,则可以执行

if user and user.address and user.address.streetname and user.address.streetname == 'Target':
    #Do something/

或者,您也可以这样做:

address = getattr(user, 'address', None) if user else None
if address and getattr(address, 'streetname', '') == 'Target':
    #do something 

答案 1 :(得分:1)

使用duck typing并创建一个sentinel对象,该对象保证使用不匹配的streetname属性来代替不可用的user.address

poor_user_address = type('', (), {'streetname': None})()
if getattr(user, 'address', poor_user_address).streetname == "Target":
    ...

type的调用会创建一个带有类变量streetname的最小类;课程的其他细节是无关紧要的。使用duck typing,poor_user_address是不同类的实例并不重要,只要它表现出相同的行为即可。在这种情况下,唯一预期的行为是具有可以与“目标”进行比较的streetname属性。

答案 2 :(得分:0)

Here's another stackoverflow question that answers this

相关部分将是:hasattr(用户,'地址')

如果在访问该属性之前将其添加到if,则可以维护if / else流。

答案 3 :(得分:0)

try:
    streetname = user.address.streetname
except DoesNotExist:
    streetname = None
    # or:
    # streetname = NonexistenceSentinel()

if streetname == 'Target':
    pass
elif:
    ...
else:
    ...

但是你可能正在寻找的是一些语法糖,让你不要把它放在任何地方。这是一个可以让你这样做的食谱:

# 'Stupid' object that just returns itself.
# Any attribute will just return itself.
class SentinelObject(object):
    __slots__ = []
    def __init__(self):
        pass

    def __getattr__(self, key):
        return self

    def __nonzero__(self):
        return False


def delegate_specials(specials):
    specialnames = ['__%s__'%s for s in specials.split()]
    def wrapit(cls, method):
        return lambda self, *args, **kwargs: getattr(self._original_obj, method)(*args, **kwargs) 
    def dowrap(cls):
        for n in specialnames:
            setattr(cls, n,
                wrapit(cls, n))
        return cls
    return dowrap

@delegate_specials('getitem setitem iter add sub mul div repr str len')
class SafeLookupObject(object):
    __slots__ = ['_original_obj', '_sentinel_default']
    __original_names__ = ['_original_obj', '_sentinel_default']
    def __init__(self, original_obj, sentinel_default=SentinelObject()):
        self._original_obj = original_obj
        self._sentinel_default = sentinel_default

    def __getattr__(self, key):
        if key in self.__original_names__:
            return object.__getattr__(self, key)
        else:
            try:
                val = getattr(self._original_obj, key)
                if callable(val):
                    return val
                else:
                    return SafeLookupObject(val, self._sentinel_default)
            except AttributeError:
                return self._sentinel_default

    def __setattr__(self, key, value):
        if key in self.__original_names__:
            return object.__setattr__(self, key, value)
        else:
            return setattr(self._original, key, value)

可能不完美,第一次通过看起来不错。

这是做什么的:传入一个原始对象和一个默认值。默认值是一个特殊的SentinelObject(一分钟内更多)。仅适用于getattr,如果它不存在,则返回sentinel值。如果它确实存在,它会检查它是否可以调用。如果它是可调用的(即函数),则直接返回它。如果没有,它将它包装在SafeLookupObject中并返回它。

目的是,如果要查找x.y.z,可以将x包装在SafeLookupObject中,然后x.y也将自动包装,一直向下,因此,如果它在列表中的任何地方失败,那么该值将被替换为sentinel对象。

因此特殊的SentinelObject,它为你传入的任何属性返回自己。这与上面的内容使它完全递归。

即。假设您使用a.b.c.d查找a是安全的。 a.b没问题,但b中不存在c。默认设置为Nonea.b.c会返回None,但a.b.c.d会引发异常。

如果使用SentinelObject作为默认值,则a.b.c将返回SentinelObject,它们都是布尔值False,并且可以匹配以确定不存在的属性。 <{1}}也返回相同的SentinelObject,因此它现在完全安全。

相关问题