2014-01-24 43 views
0

比如我得到這個if聲明:如何處理Python異常裏面的if語句

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

但並不是所有的用戶都有足夠的錢有一個地址,以便它可以拋出一個異常 在我來說,一個Django DoesNotExist例外。在這種情況下,它應該假設爲假。

如何在這個地方處理異常而不會中斷elif else流?

+0

在'try'中包裝整個'if ... else'並捕獲'DoesNotExist'異常? –

+0

你可以請你附上你的模特課嗎? – Silwest

+0

@PauloBu這正是我想要避免 –

回答

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 
+0

這似乎是最好的方法。 – Daenyth

+0

這似乎是最好的辦法,今天晚些時候會嘗試。我的觀點是避免在if之前寫入整個'try catch' - 它使代碼看起來很雜亂,而且不太可讀 –

+0

如果我使用第一個方法錯誤點來行如果我使用getattr錯誤點getattr行 '地址= getattr(用戶,'地址',無)如果用戶別無' –

1

使用鴨打字和創建保證具有非定點對象匹配streetname屬性以代替不可用的user.address

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

type呼叫創建了一個最小的類與類變量streetname;該課程的其餘細節是無關緊要的。用鴨子打字,poor_user_address是一個不同類的實例,只要它表現出相同的行爲即可。在這種情況下,唯一預期的行爲是將streetname屬性與「目標」進行比較。

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) 

可能不完美,第一遍看起來不錯。

這是做什麼的:你傳入一個原始對象和一個默認的val。默認的val是一個特殊的SentinelObject(在一分鐘內更多)。只有getattr,如果它不存在,它將返回標記值。如果它確實存在,它會檢查它是否可以調用。如果它是可調用的(即一個函數),它會直接返回它。如果沒有,則將其包裝在SafeLookupObject中並返回。

的目的是,如果你想查找x.y.z,你可以只是包裝x在SafeLookupObject,然後x.y將被自動包裝爲好,一路下來,所以如果它在列表中的任何地方發生故障,該值將被替換爲哨兵對象。

因此,特殊的SentinelObject會自動返回您傳入的任何屬性。這與上面的使它完全遞歸。

即假設你查找a.b.c.da作爲安全。a.b是可以的,但是然後c不存在於b中。默認爲None,a.b.c返回None,但a.b.c.d會引發異常。

如果您使用SentinelObject作爲默認值,則a.b.c會返回一個SentinelObject,它們都是布爾值False,並且可以進行匹配以確定不存在的屬性。 a.b.c.d也返回相同的SentinelObject,因此它現在完全安全。