比如我得到這個if
聲明:如何處理Python異常裏面的if語句
if user.address.streetname == 'Target':
pass
elif:
(...)
else:
(...)
但並不是所有的用戶都有足夠的錢有一個地址,以便它可以拋出一個異常 在我來說,一個Django DoesNotExist
例外。在這種情況下,它應該假設爲假。
如何在這個地方處理異常而不會中斷elif else流?
比如我得到這個if
聲明:如何處理Python異常裏面的if語句
if user.address.streetname == 'Target':
pass
elif:
(...)
else:
(...)
但並不是所有的用戶都有足夠的錢有一個地址,以便它可以拋出一個異常 在我來說,一個Django DoesNotExist
例外。在這種情況下,它應該假設爲假。
如何在這個地方處理異常而不會中斷elif else流?
Here's another stackoverflow question that answers this
相關部分是:hasattr(用戶, '地址')
如果您添加到您,如果訪問屬性,才能維持的if/else流。
如果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
這似乎是最好的方法。 – Daenyth
這似乎是最好的辦法,今天晚些時候會嘗試。我的觀點是避免在if之前寫入整個'try catch' - 它使代碼看起來很雜亂,而且不太可讀 –
如果我使用第一個方法錯誤點來行如果我使用getattr錯誤點getattr行 '地址= getattr(用戶,'地址',無)如果用戶別無' –
使用鴨打字和創建保證具有非定點對象匹配streetname
屬性以代替不可用的user.address
。
poor_user_address = type('',(), {'streetname': None})()
if getattr(user, 'address', poor_user_address).streetname == "Target":
...
到type
呼叫創建了一個最小的類與類變量streetname
;該課程的其餘細節是無關緊要的。用鴨子打字,poor_user_address
是一個不同類的實例,只要它表現出相同的行爲即可。在這種情況下,唯一預期的行爲是將streetname
屬性與「目標」進行比較。
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.d
和a
作爲安全。a.b
是可以的,但是然後c
不存在於b中。默認爲None
,a.b.c
返回None
,但a.b.c.d
會引發異常。
如果您使用SentinelObject作爲默認值,則a.b.c
會返回一個SentinelObject,它們都是布爾值False,並且可以進行匹配以確定不存在的屬性。 a.b.c.d
也返回相同的SentinelObject,因此它現在完全安全。
在'try'中包裝整個'if ... else'並捕獲'DoesNotExist'異常? –
你可以請你附上你的模特課嗎? – Silwest
@PauloBu這正是我想要避免 –