[英]How to catch the lookup of non-existent nested variables on a Python class?
[英]How to raise exception for non-existent class member?
我有一個自動創建包裝數據庫表的Python類的方法,其類成員與表中的字段具有相同的名稱。 類文件如下所示:
class CpsaUpldBuildChrgResultSet(Recordset):
def __init__(self, connection):
super().__init__(connection)
self.DefaultTableName = 'cpsa_upld_build_chrg_result'
self._keyFields.append('j_trans_seq')
self._keyFields.append('j_index')
@property
def j_trans_seq(self):
return self.GetValue('j_trans_seq')
@j_trans_seq.setter
def j_trans_seq(self, value):
self.SetKeyValue('j_trans_seq', value)
@property
def j_index(self):
return self.GetValue('j_index')
@j_index.setter
def j_index(self, value):
self.SetKeyValue('j_index', value)
我剛剛發現,如果我嘗試為不存在的類成員設置一個值,例如J_TRANS_SEQ,則不會拋出任何異常。 我可以添加到此類中,以便嘗試訪問不存在的成員會引發異常嗎?
您可以向類中添加__setattr__
方法,只要分配了無效AttributeError
就會引發AttributeError
。 我不確定你究竟想要確定哪些屬性是有效的,哪些屬性不是,但是一種方法可能是這樣的:
def __setattr__(self, name, value):
if hasattr(self, name):
super().setattr(name, value)
else:
raise AttributeError("{} object has no attribute {!r}".format(type(self), name))
這假定可以查找的任何屬性也可以分配給它。 如果除非在getter之前調用setter,否則你的property
的getter不起作用可能會破壞。 它也可能過於寬松,因為它允許設置覆蓋類屬性的實例屬性(例如__init__
)。 另一種方法可能是根據已知屬性的白名單檢查名稱(但一定要包括繼承類機制所需的屬性,如DefaultTableName
和_keyFields
)。
我認為@Blckknght有正確的想法,但在他的回答中遺漏了一些重要的細節 - 這樣就有類屬性(類成員)如何在第一次設置時,當它們不存在時,例如在類的典型場景中__init__()
方法執行。 這是一個更完整的解決方案,在Python 3中可以解決這個問題。
它還展示了如何最小化一堆重復屬性的編碼。
class Recordset(object):
def __init__(self, connection):
print('Recordset.__init__({!r}) called'.format(connection))
def SetKeyValue(self, name, value):
print('SetKeyValue({!r}, {!r}) called'.format(name, value))
def GetValue(self, name):
print('GetValue({!r}) called'.format(name))
def fieldname_property(name):
storage_name = '_' + name
@property
def prop(self):
return self.GetValue(storage_name)
@prop.setter
def prop(self, value):
self.SetKeyValue(storage_name, value)
return prop
class CpsaUpldBuildChrgResultSet(Recordset):
# define properties for valid fieldnames
j_trans_seq = fieldname_property('j_trans_seq')
j_index = fieldname_property('j_index')
def __init__(self, connection):
super().__init__(connection)
self._setter('DefaultTableName', 'cpsa_upld_build_chrg_result')
def __setattr__(self, name, value):
if hasattr(self, name):
self._setter(name, value)
else:
raise AttributeError("No field named %r" % name)
def _setter(self, name, value):
"""Provides way to intentionally bypass overloaded __setattr__."""
super().__setattr__(name, value)
print('start')
db_table = CpsaUpldBuildChrgResultSet('SomeConnection')
print('assigning attributes...')
db_table.j_trans_seq = 42 # OK
db_table.j_index = 13 # OK
db_table.J_TRANS_SEQ = 99 # -> AttributeError: No field named 'J_TRANS_SEQ'
print('done')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.