跳转到主要内容

数据容器类的通用接口

项目描述

itemadapter

version pyversions actions codecov

ItemAdapter 类是对数据容器对象的包装,提供了一种通用的接口,以统一的方式处理不同类型的数据对象,无论它们的底层实现如何。

目前支持的类型包括

此外,还支持与任意类型交互,通过实现预定义的接口(参见 扩展 itemadapter)。


要求

  • Python 3.8+
  • scrapy:可选,用于与 scrapy 项目交互
  • attrs:可选,用于与基于 attrs 的项目交互
  • pydantic:可选,用于与基于 pydantic 的项目交互(当前尚不支持 pydantic>=2

安装

itemadapter 可在 PyPI 上找到,可以使用 pip 安装

pip install itemadapter

许可

itemadapter 采用 BSD-3 许可证分发。


基本用法

以下是一个使用 dataclass 对象的简单示例。考虑以下类型定义

>>> from dataclasses import dataclass
>>> from itemadapter import ItemAdapter
>>> @dataclass
... class InventoryItem:
...     name: str
...     price: float
...     stock: int
>>>

可以像字典一样处理 ItemAdapter 对象

>>> obj = InventoryItem(name='foo', price=20.5, stock=10)
>>> ItemAdapter.is_item(obj)
True
>>> adapter = ItemAdapter(obj)
>>> len(adapter)
3
>>> adapter["name"]
'foo'
>>> adapter.get("price")
20.5
>>>

包装的对象将被就地修改

>>> adapter["name"] = "bar"
>>> adapter.update({"price": 12.7, "stock": 9})
>>> adapter.item
InventoryItem(name='bar', price=12.7, stock=9)
>>> adapter.item is obj
True
>>>

转换为字典

ItemAdapter 类提供了 asdict 方法,该方法递归地将嵌套项目转换为字典。考虑以下示例

>>> from dataclasses import dataclass
>>> from itemadapter import ItemAdapter
>>> @dataclass
... class Price:
...     value: int
...     currency: str
>>> @dataclass
... class Product:
...     name: str
...     price: Price
>>>
>>> item = Product("Stuff", Price(42, "UYU"))
>>> adapter = ItemAdapter(item)
>>> adapter.asdict()
{'name': 'Stuff', 'price': {'value': 42, 'currency': 'UYU'}}
>>>

请注意,仅将适配器对象传递给内置的 dict 也可以,但它不会递归地遍历对象并将嵌套项目转换为字典

>>> dict(adapter)
{'name': 'Stuff', 'price': Price(value=42, currency='UYU')}
>>>

API 参考

内置适配器

以下适配器是默认包含的

  • itemadapter.adapter.ScrapyItemAdapter:处理 Scrapy 项目
  • itemadapter.adapter.DictAdapter:处理 Python 字典
  • itemadapter.adapter.DataclassAdapter:处理 dataclass 对象
  • itemadapter.adapter.AttrsAdapter:处理 attrs 对象
  • itemadapter.adapter.PydanticAdapter:处理 pydantic 对象

itemadapter.adapter.ItemAdapter(item: Any)

这是包的主要入口点。通常,用户代码使用此类包装一个项目,并使用提供的接口处理它。ItemAdapter 实现了 MutableMapping 接口,提供了一个类似 dict 的 API 来操作它所包装的对象的数据(该对象将被就地修改)。

属性

类属性 ADAPTER_CLASSES: Iterable

存储当前已注册的适配器类。

适配器注册的顺序很重要。为特定项目创建 ItemAdapter 对象时,将按顺序遍历已注册的适配器,并使用第一个适配器类(对于其 is_item 类方法的 item 参数返回 True 的类)执行后续操作。默认顺序在 内置适配器 部分中定义。

默认实现使用 collections.deque 支持高效地向两端添加/删除适配器类,但如果您正在派生子类(有关更多信息,请参见 扩展 itemadapter 部分),则任何其他可迭代对象(例如 listtuple)都将有效。

方法

类方法 is_item(item: Any) -> bool

如果任何已注册的适配器可以处理项目(即,如果其中任何一个返回 True 对于其 is_item 方法与 item 作为参数),则返回 True,否则返回 False

类方法 is_item_class(item_class: type) -> bool

如果任何已注册的适配器可以处理项目类(即,如果其中任何一个返回 True 对于其 is_item_class 方法与 item_class 作为参数),则返回 True,否则返回 False

类方法 get_field_meta_from_class(item_class: type, field_name: str) -> MappingProxyType

返回一个 types.MappingProxyType 对象,该对象是一个只读映射,包含有关给定字段的元数据。如果项目类不支持字段元数据,或者没有给定字段的元数据,则返回一个空对象。

返回值取自以下来源,具体取决于项目类型

类方法 get_field_names_from_class(item_class: type) -> Optional[list[str]]

返回一个包含为项目类定义的所有字段名称的列表。如果项目类不支持预先定义字段,则返回 None。

get_field_meta(field_name: str) -> MappingProxyType

如果可用,则返回给定字段的元数据。除非在自定义适配器类中重写,否则默认情况下此方法调用适配器的 get_field_meta_from_class 方法,并传递包装项目的类。

field_names() -> collections.abc.KeysView

返回一个包含为项目定义的所有字段名称的 keys view

asdict() -> dict

返回一个包含适配器内容的 dict 对象。这比调用 dict(adapter) 略微不同,因为它递归地应用于嵌套项目(如果有的话)。

函数 itemadapter.utils.is_item(obj: Any) -> bool

如果给定的对象属于(至少)支持的类型之一,则返回 True,否则返回 False。这是一个别名,建议使用 itemadapter.adapter.ItemAdapter.is_item 类方法以获得更好的性能。

函数 itemadapter.utils.get_field_meta_from_class(item_class: type, field_name: str) -> types.MappingProxyType

itemadapter.adapter.ItemAdapter.get_field_meta_from_class 的别名


元数据支持

scrapy.item.Itemdataclassattrspydantic 对象允许定义任意字段元数据。这可以通过一个 MappingProxyType 对象访问,该对象可以通过使用 itemadapter.adapter.ItemAdapter.get_field_meta 从项目实例中检索,或者使用 itemadapter.adapter.ItemAdapter.get_field_meta_from_class 方法(或其别名 itemadapter.utils.get_field_meta_from_class)从项目类中检索。数据源取决于底层类型(请参阅 ItemAdapter.get_field_meta_from_class 的文档)。

scrapy.item.Item 对象

>>> from scrapy.item import Item, Field
>>> from itemadapter import ItemAdapter
>>> class InventoryItem(Item):
...     name = Field(serializer=str)
...     value = Field(serializer=int, limit=100)
...
>>> adapter = ItemAdapter(InventoryItem(name="foo", value=10))
>>> adapter.get_field_meta("name")
mappingproxy({'serializer': <class 'str'>})
>>> adapter.get_field_meta("value")
mappingproxy({'serializer': <class 'int'>, 'limit': 100})
>>>

dataclass 对象

>>> from dataclasses import dataclass, field
>>> @dataclass
... class InventoryItem:
...     name: str = field(metadata={"serializer": str})
...     value: int = field(metadata={"serializer": int, "limit": 100})
...
>>> adapter = ItemAdapter(InventoryItem(name="foo", value=10))
>>> adapter.get_field_meta("name")
mappingproxy({'serializer': <class 'str'>})
>>> adapter.get_field_meta("value")
mappingproxy({'serializer': <class 'int'>, 'limit': 100})
>>>

attrs 对象

>>> import attr
>>> @attr.s
... class InventoryItem:
...     name = attr.ib(metadata={"serializer": str})
...     value = attr.ib(metadata={"serializer": int, "limit": 100})
...
>>> adapter = ItemAdapter(InventoryItem(name="foo", value=10))
>>> adapter.get_field_meta("name")
mappingproxy({'serializer': <class 'str'>})
>>> adapter.get_field_meta("value")
mappingproxy({'serializer': <class 'int'>, 'limit': 100})
>>>

pydantic 对象

>>> from pydantic import BaseModel, Field
>>> class InventoryItem(BaseModel):
...     name: str = Field(serializer=str)
...     value: int = Field(serializer=int, limit=100)
...
>>> adapter = ItemAdapter(InventoryItem(name="foo", value=10))
>>> adapter.get_field_meta("name")
mappingproxy({'serializer': <class 'str'>})
>>> adapter.get_field_meta("value")
mappingproxy({'serializer': <class 'int'>, 'limit': 100})
>>>

扩展 itemadapter

此软件包允许通过实现适配器接口来处理任意项目类

itemadapter.adapter.AdapterInterface(item: Any)

适配器的抽象基类。处理特定类型项目的适配器必须继承此类并实现其上定义的抽象方法。AdapterInterface 继承自 collections.abc.MutableMapping,因此必须实现 MutableMapping 接口的所有方法。

  • 类方法 is_item_class(cls, item_class: type) -> bool

    如果适配器可以处理给定的项目类,则返回 True,否则返回 False。抽象(强制)。

  • 类方法 is_item(cls, item: Any) -> bool

    如果适配器可以处理给定的项目,则返回 True,否则返回 False。默认实现调用 cls.is_item_class(item.__class__)

  • 类方法 get_field_meta_from_class(cls, item_class: type) -> bool

    返回给定项目类和字段名的元数据(如果有的话)。默认情况下,此方法返回一个空的 MappingProxyType 对象。如果您想根据自定义逻辑处理字段元数据,请提供自己的方法定义。有关更多信息,请参阅元数据支持部分

  • 方法 get_field_meta(self, field_name: str) -> types.MappingProxyType

    返回给定字段名的元数据(如果有的话)。通常无需重写此方法,因为基类 itemadapter.adapter.AdapterInterface 提供了一个默认实现,该实现使用包装项目的类作为参数调用 ItemAdapter.get_field_meta_from_class。有关更多信息,请参阅元数据支持部分

  • 方法 field_names(self) -> collections.abc.KeysView:

    返回项目字段名的动态视图。默认情况下,此方法返回对当前适配器调用 keys() 的结果,即它的返回值取决于 MutableMapping 接口(更具体地说,它取决于 __iter__ 的返回值)。

    如果您想获取项目所有字段(无论是否已填充),则可能需要重写此方法。例如,Scrapy 使用此方法在导出项目到 CSV 时定义列名。

注册适配器

将您的自定义适配器类添加到 itemadapter.adapter.ItemAdapter.ADAPTER_CLASSES 类属性中,以处理自定义项目类。

示例

>>> from itemadapter.adapter import ItemAdapter
>>> from tests.test_interface import BaseFakeItemAdapter, FakeItemClass
>>>
>>> ItemAdapter.ADAPTER_CLASSES.appendleft(BaseFakeItemAdapter)
>>> item = FakeItemClass()
>>> adapter = ItemAdapter(item)
>>> adapter
<ItemAdapter for FakeItemClass()>
>>>

多个适配器类

如果您需要针对不同情况有不同的处理程序和/或优先级,可以继承 ItemAdapter 类并设置所需的 ADAPTER_CLASSES 属性。

示例

>>> from itemadapter.adapter import (
...     ItemAdapter,
...     AttrsAdapter,
...     DataclassAdapter,
...     DictAdapter,
...     PydanticAdapter,
...     ScrapyItemAdapter,
... )
>>> from scrapy.item import Item, Field
>>>
>>> class BuiltinTypesItemAdapter(ItemAdapter):
...     ADAPTER_CLASSES = [DictAdapter, DataclassAdapter]
...
>>> class ThirdPartyTypesItemAdapter(ItemAdapter):
...     ADAPTER_CLASSES = [AttrsAdapter, PydanticAdapter, ScrapyItemAdapter]
...
>>> class ScrapyItem(Item):
...     foo = Field()
...
>>> BuiltinTypesItemAdapter.is_item(dict())
True
>>> ThirdPartyTypesItemAdapter.is_item(dict())
False
>>> BuiltinTypesItemAdapter.is_item(ScrapyItem(foo="bar"))
False
>>> ThirdPartyTypesItemAdapter.is_item(ScrapyItem(foo="bar"))
True
>>>

更多示例

scrapy.item.Item 对象

>>> from scrapy.item import Item, Field
>>> from itemadapter import ItemAdapter
>>> class InventoryItem(Item):
...     name = Field()
...     price = Field()
...
>>> item = InventoryItem(name="foo", price=10)
>>> adapter = ItemAdapter(item)
>>> adapter.item is item
True
>>> adapter["name"]
'foo'
>>> adapter["name"] = "bar"
>>> adapter["price"] = 5
>>> item
{'name': 'bar', 'price': 5}
>>>

dict

>>> from itemadapter import ItemAdapter
>>> item = dict(name="foo", price=10)
>>> adapter = ItemAdapter(item)
>>> adapter.item is item
True
>>> adapter["name"]
'foo'
>>> adapter["name"] = "bar"
>>> adapter["price"] = 5
>>> item
{'name': 'bar', 'price': 5}
>>>

dataclass 对象

>>> from dataclasses import dataclass
>>> from itemadapter import ItemAdapter
>>> @dataclass
... class InventoryItem:
...     name: str
...     price: int
...
>>> item = InventoryItem(name="foo", price=10)
>>> adapter = ItemAdapter(item)
>>> adapter.item is item
True
>>> adapter["name"]
'foo'
>>> adapter["name"] = "bar"
>>> adapter["price"] = 5
>>> item
InventoryItem(name='bar', price=5)
>>>

attrs 对象

>>> import attr
>>> from itemadapter import ItemAdapter
>>> @attr.s
... class InventoryItem:
...     name = attr.ib()
...     price = attr.ib()
...
>>> item = InventoryItem(name="foo", price=10)
>>> adapter = ItemAdapter(item)
>>> adapter.item is item
True
>>> adapter["name"]
'foo'
>>> adapter["name"] = "bar"
>>> adapter["price"] = 5
>>> item
InventoryItem(name='bar', price=5)
>>>

pydantic 对象

>>> from pydantic import BaseModel
>>> from itemadapter import ItemAdapter
>>> class InventoryItem(BaseModel):
...     name: str
...     price: int
...
>>> item = InventoryItem(name="foo", price=10)
>>> adapter = ItemAdapter(item)
>>> adapter.item is item
True
>>> adapter["name"]
'foo'
>>> adapter["name"] = "bar"
>>> adapter["price"] = 5
>>> item
InventoryItem(name='bar', price=5)
>>>

变更日志

请参阅完整变更日志

项目详细信息


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装软件包的信息。

源分发

itemadapter-0.9.0.tar.gz (18.9 kB 查看哈希值)

上传时间

构建分发

itemadapter-0.9.0-py3-none-any.whl (11.1 kB 查看哈希值)

上传时间 Python 3

由以下支持

AWSAWS云计算和安全赞助商DatadogDatadog监控FastlyFastlyCDNGoogleGoogle下载分析MicrosoftMicrosoftPSF赞助商PingdomPingdom监控SentrySentry错误日志StatusPageStatusPage状态页面