Как предложили комментаторы, и из-за преднамеренного различия между свойствами и методами, а также из-за того, над чем я работаю, есть и данные, и поведение, я создал специальный класс для этого.
Я публикую и классовые, и модульные тесты поведения.Скорее всего, этот код подвержен ошибкам, но он выполняет свою работу для текущей версии любимого проекта.Любые советы и потенциальные проблемы с юзабилити и масштабированием приветствуются.
class Correspondence(dict):
"""A class for Correspondence data structure, see Chapter 2 of the book."""
def update(self, *args, **kwargs):
"""Update the correspondence object with the unique keys."""
try:
keyid = args[0]['target'] + args[0]['source'] + args[0]['condition']
self[keyid] = args[0]
except KeyError:
raise TypeError('The input should contain source, target, \
condition and truthvalue as keys of the input dictionary')
def filter(self, source=None, target=None, condition=None, truthvalue=None):
"""Filter Correspondence object. (target ⇐ source))
Input:
source: filtering condition, source
target: filtering condition, target
condition: filtering conidtion, correspondence condition
truthvalue: filtering condition, truthvalue excluding
Output:
output: a Correspondence instance
"""
filters = {
'source': source,
'target': target,
'condition': condition,
'truthvalue': truthvalue}
filters = {k: v for k, v in filters.items() if v is not None}
if not bool(filters):
return self
else:
_correspondence = copy.deepcopy(self)
# iterate over filters, followed by iteration over items
# if the conditions are not satisfied, then items are removed
# matrix-based computation would be more efficient,
# but would do for now unless performance issues
for filter_key, filter_value in filters.items():
for key, value in self.items():
if value[filter_key] is not filter_value:
del _correspondence[key]
return _correspondence
Юнит-тесты
def test_correspondence_structure_and_methods(self):
# check if correspondence has the right structure
BA_correspondence = {
'source': 'A.uuid',
'target': 'B.uuid',
'condition': 'the condition',
'truthvalue': 'true'}
CA_correspondence = {
'source': 'A.uuid',
'target': 'C.uuid',
'condition': 'the condition',
'truthvalue': 'true'}
CA_correspondence_wrong = {
'sources': 'A.uuid', # the key should be "source"
'target': 'C.uuid',
'condition': 'the condition',
'truthvalue': 'true'}
BA_correspondence_upd = {
'source': 'A.uuid',
'target': 'B.uuid',
'condition': 'the condition',
'truthvalue': 'unverifiable'}
correspondence = fabric.Correspondence()
# test if Correspondence.update() processes the right data
self.assertRaises(
TypeError,
correspondence.update,
CA_correspondence_wrong)
correspondence.update(BA_correspondence)
# (B ⇐ A)
self.assertDictEqual(
{'B.uuidA.uuidthe condition': BA_correspondence},
correspondence)
# (B ⇐ A) ⋅ (C ⇐ A)
correspondence.update(CA_correspondence)
self.assertDictEqual(
{
'B.uuidA.uuidthe condition': BA_correspondence,
'C.uuidA.uuidthe condition': CA_correspondence},
correspondence)
# updated truthvalue with the same source, target, and condition
# (B ⇐ A) ⋅ (C ⇐ A)
correspondence.update(BA_correspondence_upd)
self.assertDictEqual(
{
'B.uuidA.uuidthe condition': BA_correspondence_upd,
'C.uuidA.uuidthe condition': CA_correspondence},
correspondence)
# filter correspondence
self.assertDictEqual(
{
'B.uuidA.uuidthe condition': BA_correspondence_upd,
'C.uuidA.uuidthe condition': CA_correspondence},
correspondence.filter())
self.assertDictEqual(
{
'B.uuidA.uuidthe condition': BA_correspondence_upd},
correspondence.filter(target='B.uuid'))
self.assertDictEqual(
{
'B.uuidA.uuidthe condition': BA_correspondence_upd,
'C.uuidA.uuidthe condition': CA_correspondence},
correspondence.filter(source='A.uuid'))
self.assertDictEqual(
{
'B.uuidA.uuidthe condition': BA_correspondence_upd,
'C.uuidA.uuidthe condition': CA_correspondence},
correspondence.filter(condition='the condition'))
self.assertDictEqual(
{
'C.uuidA.uuidthe condition': CA_correspondence},
correspondence.filter(truthvalue='true'))
self.assertDictEqual(
{
'B.uuidA.uuidthe condition': BA_correspondence_upd},
correspondence.filter(source='A.uuid', truthvalue='unverifiable'))
self.assertDictEqual(
{
'B.uuidA.uuidthe condition': BA_correspondence_upd},
correspondence.
filter(source='A.uuid').filter(truthvalue='unverifiable'))