Dav*_*542 5 python inheritance class python-3.x
我希望使用 django 模型中使用的模式来Model.objects.filter(...)构建跨数据的过滤器。这可能是 pandas 的一个很好的用例,但我更感兴趣的是在尝试之前改进我的 python(首先)。
如果我有以下数据:
DATA = [
{'id': 1, 'name': 'brad', 'color':'red'},
{'id': 2, 'name': 'sylvia', 'color':'blue'},
]
Run Code Online (Sandbox Code Playgroud)
我想构建类似于以下内容的东西:
class MyData:
objects = <something>
Run Code Online (Sandbox Code Playgroud)
并将objects等效项设置为“ModelManager”,然后从那里进行过滤,以便我可以调用:
MyData.objects.filter(id>1)
Run Code Online (Sandbox Code Playgroud)
并得到:
[
{'id': 2, 'name': 'sylvia', 'color':'blue'}
]
Run Code Online (Sandbox Code Playgroud)
当然,我可以做一些简单的事情:
res = [_ for _ in DATA if _['id'] > 1]
Run Code Online (Sandbox Code Playgroud)
但我对设计模式本身更感兴趣——这个例子的琐碎本质只是为了展示我想要完成的任务。
正确执行此操作的良好基本方法是什么?这是 django 中的相关类:https://github.com/django/django/blob/master/django/db/models/query.py#L185。
OP 想要这样做MyData.objects.filter(id>1)。
面对现实吧。
\n\n问题是 Python 是贪婪的(急切地计算表达式),而不是像 Haskell 那样懒惰。
\n观看David Beazley - 从头开始的 Lambda 演算 - PyCon 2019,了解令人费解的 \xce\xbb 事情。
Pythonid > 1在调用之前进行计算filter。如果我们现在可以停止计算,我们可以将未计算的表达式传递给函数filter。
但是,如果我们将表达式包含在函数中,则可以将表达式求值延迟到需要时为止。这就是想法。
\n\n如果我们能够实现它,函数接口就会是filter(lambda: id > 1)。\n这个接口将非常通用,因为任何 Python 表达式都可以传递和滥用。
实施;
\n\n如果我们使用表达式调用 lambda 或任何其他函数,Python 会在本地、封闭、全局作用域中id > 1查找名称,或者根据调用函数的上下文查找名称。idbuiltins
如果我们可以在idPython 查找之前在查找路径中的某个位置引入一个具有该名称的对象,我们就可以重新定义表达式的语义。 idbuiltins
我将用它来eval计算给定上下文中的表达式。
DATA = [\n {\'id\': 1, \'name\': \'brad\', \'color\':\'red\'},\n {\'id\': 2, \'name\': \'sylvia\', \'color\':\'blue\'},\n]\n\ndef myfilter(a_lambda):\n return filter(lambda obj: eval(a_lambda.__code__, obj.copy()),\n DATA)\nRun Code Online (Sandbox Code Playgroud)\n\n我将 a 传递dict.copy给eval因为eval修改了它的globals对象。
Model在课堂上查看它的实际应用
In [1]: class Data(Model):\n ...: name = str()\n ...: id = int()\n ...: color = str()\n ...: \n\nIn [2]: Data.objects.create(**{"id": 1, "name": "brad", "color": "red"})\n\nIn [3]: Data.objects.create(**{"id": 2, "name": "sylvia", "color": "blue"})\n\nIn [4]: Data.objects.create(**{"id": 3, "name": "paul", "color": "red"})\n\nIn [5]: Data.objects.create(**{"id": 4, "name": "brandon", "color": "yello"})\n\nIn [6]: Data.objects.create(**{"id": 5, "name": "martin", "color": "green"})\n\nIn [7]: Data.objects.create(**{"id": 6, "name": "annie", "color": "gray"})\n\nIn [8]: pprint([vars(obj) for obj in Data.objects.filter(lambda: id == 1)])\n[{\'color\': \'red\', \'id\': 1, \'name\': \'brad\'}]\n\nIn [9]: pprint([vars(obj) for obj in Data.objects.filter(lambda: 1 <= id <= 2)])\n[{\'color\': \'red\', \'id\': 1, \'name\': \'brad\'},\n {\'color\': \'blue\', \'id\': 2, \'name\': \'sylvia\'}]\n\nIn [10]: pprint([vars(obj) for obj in Data.objects.filter(lambda: color == "blue")])\n[{\'color\': \'blue\', \'id\': 2, \'name\': \'sylvia\'}]\n\nIn [11]: pprint([vars(obj) for obj in Data.objects.filter(lambda: "e" in color and (name is "brad" or name is "sylvia"))])\n[{\'color\': \'red\', \'id\': 1, \'name\': \'brad\'},\n {\'color\': \'blue\', \'id\': 2, \'name\': \'sylvia\'}]\n\nIn [12]: pprint([vars(obj) for obj in Data.objects.filter(lambda: id % 2 == 1)])\n[{\'color\': \'red\', \'id\': 1, \'name\': \'brad\'},\n {\'color\': \'red\', \'id\': 3, \'name\': \'paul\'},\n {\'color\': \'green\', \'id\': 5, \'name\': \'martin\'}]\nRun Code Online (Sandbox Code Playgroud)\n\n该类Data继承自Model. 给出Model了Data方法__init__和一个名为的类属性objects,该属性指向MetaManager一个描述符实例。
在从子类访问属性时,将实例MetaManager返回Manager给子类。标识访问类并将其传递给实例。\n处理对象创建、持久化和获取。ModelobjectsMetaMangerManagerManager
为了简单起见,db 被实现为 的类属性Manager。
为了阻止通过函数滥用全局对象,filter如果未传递 lambda,函数会引发异常。
from collections import defaultdict\nfrom collections.abc import Callable\n\n\nclass MetaManager:\n def __get__(self, obj, objtype):\n if obj is None:\n return Manager(objtype)\n else:\n raise AttributeError(\n "Manger isn\'t accessible via {} instances".format(objtype)\n )\n\n\nclass Manager:\n _store = defaultdict(list)\n\n def __init__(self, client):\n self._client = client\n self._client_name = "{}.{}".format(client.__module__, client.__qualname__)\n\n def create(self, **kwargs):\n self._store[self._client_name].append(self._client(**kwargs))\n\n def all(self):\n return (obj for obj in self._store[self._client_name])\n\n def filter(self, a_lambda):\n if a_lambda.__code__.co_name != "<lambda>":\n raise ValueError("a lambda required")\n\n return (\n obj\n for obj in self._store[self._client_name]\n\n if eval(a_lambda.__code__, vars(obj).copy())\n )\n\n\nclass Model:\n objects = MetaManager()\n\n def __init__(self, **kwargs):\n if type(self) is Model:\n raise NotImplementedError\n\n class_attrs = self.__get_class_attributes(type(self))\n\n self.__init_instance(class_attrs, kwargs)\n\n def __get_class_attributes(self, cls):\n attrs = vars(cls)\n if "objects" in attrs:\n raise AttributeError(\n \'class {} has an attribute named "objects" of type "{}"\'.format(\n type(self), type(attrs["objects"])\n )\n )\n attrs = {\n attr: obj\n for attr, obj in vars(cls).items()\n if not attr.startswith("_") and not isinstance(obj, Callable)\n }\n return attrs\n\n def __init_instance(self, attrs, kwargs_dict):\n for key, item in kwargs_dict.items():\n if key not in attrs:\n raise TypeError(\'Got an unexpected key word argument "{}"\'.format(key))\n if isinstance(item, type(attrs[key])):\n setattr(self, key, item)\n else:\n raise TypeError(\n "Expected type {}, got {}".format(type(attrs[key]), type(item))\n )\n\n\nif __name__ == "__main__":\n from pprint import pprint\n\n class Data(Model):\n name = str()\n id = int()\n color = str()\n\n Data.objects.create(**{"id": 1, "name": "brad", "color": "red"})\n Data.objects.create(**{"id": 2, "name": "sylvia", "color": "blue"})\n Data.objects.create(**{"id": 3, "name": "paul", "color": "red"})\n Data.objects.create(**{"id": 4, "name": "brandon", "color": "yello"})\n Data.objects.create(**{"id": 5, "name": "martin", "color": "green"})\n Data.objects.create(**{"id": 6, "name": "annie", "color": "gray"})\n\n pprint([vars(obj) for obj in Data.objects.filter(lambda: id == 1)])\n pprint([vars(obj) for obj in Data.objects.filter(lambda: 1 <= id <= 2)])\n pprint([vars(obj) for obj in Data.objects.filter(lambda: color == "blue")])\n pprint(\n [\n vars(obj)\n for obj in Data.objects.filter(\n lambda: "e" in color and (name is "brad" or name is "sylvia")\n )\n ]\n )\n pprint([vars(obj) for obj in Data.objects.filter(lambda: id % 2 == 1)])\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
13049 次 |
| 最近记录: |