深入理解Python数据模型

Python 的数据模型是基于特殊方法的,这是因为这些特殊方法提供了一种非常强大的机制,它允许自定义类型去模拟和表现得如同 Python 内置类型一样。这样的设计允许开发者用 Python 来实现几乎任何数据结构,并确保它可以与 Python 的其他部分以自然和一致的方式集成。

1.基本集合类型的接口

图中的所有类型都是抽象基类(abstract base classes

每个顶端的抽象类都有一个特殊方法。Collection ABC统一集合需要实现的三个接口:

Iterable:支持for,拆包和其他类型的迭代
Sized: 支持内置方法 len
Container: 支持操作符 in


三个非常重要的集合类型:

Sequence:规范化内置接口,例如str,list
Mapping: 通常由dict和collections.defaultdict实现
Set: 内置类型set和frozenset的接口


其中,只有序列(Sequence)是可以被反转的(Reversible),因为序列支持随意改变内容的顺序,而字典和集合不支持。

2.使用特殊方法的两个优点

1.用户使用类时不必记住标准操作的各种各样的名称。 (“如何获取元素的数量?是 .size()、.length() 还是什么函数?”)


2.可以更加方便的利用Python 丰富的标准库并避免重新发明轮子,例如 random.choice 函数。 特殊方法使得用户自定义的对象在行为上可以和内置对象无缝对接。例如,通过实现 __len____getitem__ 方法,自定义的对象可以表现得和列表或元组那样,可以使用 len() 函数和索引操作(e.g., obj[3])。

3.调用特殊方法

特殊方法是由 Python 解释器调用的,而不是用户。需要调用特殊方法,通常最好调用相关的内置函数(例如,len、iter、str 等)。这些内置函数调用相应的特殊方法,但通常提供额外的好处并且——对于内置类型——比方法调用更快。如下所示。

解释器在处理像 list、str、bytearray 这样的内置类型或像 NumPy 数组这样的扩展包时会走捷径。用 C 语言编写的 Python 可变大小的集合包括一个名为 PyVarObject 的struct,它有一个 ob_size 字段保存集合中的项的数量。因此,如果 my_object 是这些内置数据结构的实例,则 len(my_object) 会直接读取 ob_size 字段的值,这比调用方法要快得多。

4.特殊方法语法架构

  • 集合
  • 属性访问
  • 迭代(包括使用async for的异步迭代)
  • 运算符重载
  • 函数和方法的调用
  • 字符串的展示和格式化
  • 使用关键字await的异步编程
  • 对象的创建和销毁
  • 管理器上下文(包括使用async with的异步上下文管理器)

4.1. 集合(支持 len, getitem, setitem 等)

通过实现 __len__, __getitem__, __setitem__, 和 __contains__,可以创建一个自定义的集合类。

class MyCollection:
    def __init__(self, initial_data):
        self.data = list(initial_data)

    def __len__(self):
        return len(self.data)

    def __getitem__(self, position):
        return self.data[position]

    def __setitem__(self, position, value):
        self.data[position] = value

    def __contains__(self, item):
        return item in self.data

4.2 属性访问(支持动态的属性获取和设置)

通过实现 __getattr__, __setattr__, 和 __delattr__,可以控制属性的访问。

class AttributeAccess:
    def __init__(self):
        self._attributes = {}

    def __getattr__(self, item):
        return self._attributes.get(item, f"{item} not found")

    def __setattr__(self, key, value):
        if key == "_attributes":
            super().__setattr__(key, value)
        else:
            self._attributes[key] = value

    def __delattr__(self, item):
        if item in self._attributes:
            del self._attributes[item]
        else:
            raise AttributeError(f"{item} not found")

4.3 迭代(支持同步和异步迭代)

通过实现 __iter____next__ 可以支持同步迭代。实现 __aiter____anext__ 支持异步迭代。

class AsyncIterable:
    def __init__(self, data):
        self.data = data

    async def __aiter__(self):
        for item in self.data:
            yield item  # 使用 async for 需要异步生成器

# 使用
async def iterate_data():
    async for item in AsyncIterable([1, 2, 3]):
        print(item)
 

4.4 运算符重载

通过实现 __add__, __mul__, 等方法可以重载加法和乘法运算符。

class Number:
    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        if isinstance(other, Number):
            return Number(self.value + other.value)
        return NotImplemented

    def __mul__(self, other):
        if isinstance(other, Number):
            return Number(self.value * other.value)
        return NotImplemented

4.5 函数和方法的调用

通过实现 __call__,可以使得对象的实例可以像函数那样被调用。

class CallableObject:
    def __call__(self, x):
        return x * x

# 使用
obj = CallableObject()
print(obj(5))  # 输出 25

4.6 字符串的展示和格式化

通过实现 __str____repr__ 控制对象的字符串表示。

class Person:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return f"Person named {self.name}"

    def __repr__(self):
        return f"Person({self.name!r})"

4.7 使用关键字await的异步编程

通过定义 __await__ 方法可以使对象支持异步等待。

class Awaitable:
    def __await__(self):
        yield from asyncio.sleep(1).__await__()
        return 42

# 使用
async def get_result():
    result = await Awaitable()
    print(result)  # 输出 42

4.8 对象的创建和销毁

通过实现 __new____del__ 控制对象的创建和销毁过程。

class MyClass:
    def __new__(cls):
        instance = super().__new__(cls)
        print("Creating instance", instance)
        return instance

    def __del__(self):
        print("Deleting instance", self)

4.9 管理器上下文(包括异步上下文管理器)

通过实现 __enter____exit__ 方法,可以创建一个支持 with 语句的同步上下文管理器。对于异步上下文管理器,则需要实现 __aenter____aexit__

class ManagedFile:
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        self.file = open(self.filename, 'w')
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()
        if exc_type is not None:
            print(f"Exception {exc_type} occurred: {exc_val}")
        return True  # 可以防止异常向外传播

# 使用
with ManagedFile('hello.txt') as f:
    f.write('Hello, world!')

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值