好吧,另一种方法可能是实现以下内容:
Attr 是“值”的抽象。我们需要这个,因为 Python 中没有“赋值重载”(简单的 get/set 范例被用作最干净的替代方案)。 Attr 也充当“Observable”。
AttrSet 是Attrs 的“观察者”,它跟踪它们的值变化,同时有效地充当Attr-to-whatever(在我们的例子中为person)字典。
create_with_attrs 是一个工厂,通过提供的Attrs 生产看起来像命名元组的转发属性访问,因此person.name = "Ivan" 有效地产生person.name_attr.set("Ivan") 并使AttrSets 观察到这一点person 的 name 适当地重新排列它们的内部结构。
代码(已测试):
from collections import defaultdict
class Attribute(object):
def __init__(self, value):
super(Attribute, self).__init__()
self._value = value
self._notified_set = set()
def set(self, value):
old = self._value
self._value = value
for n_ch in self._notified_set:
n_ch(old_value=old, new_value=value)
def get(self):
return self._value
def add_notify_changed(self, notify_changed):
self._notified_set.add(notify_changed)
def remove_notify_changed(self, notify_changed):
self._notified_set.remove(notify_changed)
class AttrSet(object):
def __init__(self):
super(AttrSet, self).__init__()
self._attr_value_to_obj_set = defaultdict(set)
self._obj_to_attr = {}
self._attr_to_notify_changed = {}
def add(self, attr, obj):
self._obj_to_attr[obj] = attr
self._add(attr.get(), obj)
notify_changed = (lambda old_value, new_value:
self._notify_changed(obj, old_value, new_value))
attr.add_notify_changed(notify_changed)
self._attr_to_notify_changed[attr] = notify_changed
def get(self, *attr_value_lst):
attr_value_lst = attr_value_lst or self._attr_value_to_obj_set.keys()
result = set()
for attr_value in attr_value_lst:
result.update(self._attr_value_to_obj_set[attr_value])
return result
def remove(self, obj):
attr = self._obj_to_attr.pop(obj)
self._remove(attr.get(), obj)
notify_changed = self._attr_to_notify_changed.pop(attr)
attr.remove_notify_changed(notify_changed)
def __iter__(self):
return iter(self.get())
def _add(self, attr_value, obj):
self._attr_value_to_obj_set[attr_value].add(obj)
def _remove(self, attr_value, obj):
obj_set = self._attr_value_to_obj_set[attr_value]
obj_set.remove(obj)
if not obj_set:
self._attr_value_to_obj_set.pop(attr_value)
def _notify_changed(self, obj, old_value, new_value):
self._remove(old_value, obj)
self._add(new_value, obj)
def create_with_attrs(**attr_name_to_attr):
class Result(object):
def __getattr__(self, attr_name):
if attr_name in attr_name_to_attr.keys():
return attr_name_to_attr[attr_name].get()
else:
raise AttributeError(attr_name)
def __setattr__(self, attr_name, attr_value):
if attr_name in attr_name_to_attr.keys():
attr_name_to_attr[attr_name].set(attr_value)
else:
raise AttributeError(attr_name)
def __str__(self):
result = ""
for attr_name in attr_name_to_attr:
result += (attr_name + ": "
+ str(attr_name_to_attr[attr_name].get())
+ ", ")
return result
return Result()
用准备好的数据
name_and_email_lst = [("John","email1@dot.com"),
("John","email2@dot.com"),
("Jack","email3@dot.com"),
("Hack","email4@dot.com"),
]
email = AttrSet()
name = AttrSet()
for name_str, email_str in name_and_email_lst:
email_attr = Attribute(email_str)
name_attr = Attribute(name_str)
person = create_with_attrs(email=email_attr, name=name_attr)
email.add(email_attr, person)
name.add(name_attr, person)
def print_set(person_set):
for person in person_set: print person
print
下面的伪 SQL sn-p 序列给出:
从电子邮件中选择 ID
>>> print_set(email.get())
email: email3@dot.com, name: Jack,
email: email4@dot.com, name: Hack,
email: email2@dot.com, name: John,
email: email1@dot.com, name: John,
从电子邮件中选择 ID WHERE email="email1@dot.com"
>>> print_set(email.get("email1@dot.com"))
email: email1@dot.com, name: John,
从电子邮件中选择 ID WHERE email="email1@dot.com" OR email="email2@dot.com"
>>> print_set(email.get("email1@dot.com", "email2@dot.com"))
email: email1@dot.com, name: John,
email: email2@dot.com, name: John,
SELECT id FROM name WHERE name="John"
>>> print_set(name.get("John"))
email: email1@dot.com, name: John,
email: email2@dot.com, name: John,
SELECT id FROM name, email WHERE name="John" AND email="email1@dot.com"
>>> print_set(name.get("John").intersection(email.get("email1@dot.com")))
email: email1@dot.com, name: John,
更新电子邮件,名称 SET email="jon@dot.com", name="Jon"
ID 在哪里
从电子邮件中选择 ID WHERE email="email1@dot.com"
>>> person = email.get("email1@dot.com").pop()
>>> person.name = "Jon"; person.email = "jon@dot.com"
>>> print_set(email.get())
email: email3@dot.com, name: Jack,
email: email4@dot.com, name: Hack,
email: email2@dot.com, name: John,
email: jon@dot.com, name: Jon,
从电子邮件中删除,名称 WHERE id=%s
从电子邮件中选择 ID
>>> name.remove(person)
>>> email.remove(person)
>>> print_set(email.get())
email: email3@dot.com, name: Jack,
email: email4@dot.com, name: Hack,
email: email2@dot.com, name: John,