簡體   English   中英

如何為不存在的類成員引發異常?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM