python 数据模型(Data Model)

翻译源:https://docs.python.org/3/reference/datamodel.html

3. Data model

3.1. Object, values和types

Objects是Python对数据的抽象。Python程序中的所有数据都由对象或对象之间的关系表示。(在某种意义上,与冯·诺依曼的“存储程序计算机”模型一致,代码也由对象表示。)

每个对象都有一个标识、一个类型和一个值。一个对象一旦被创建,它的标识就不会改变;你可以把它看作是对象在内存中的地址。“is”运算符比较两个对象的标识;id()函数返回一个表示其标识的整数。

python 数据模型(Data Model)_第1张图片

CPython implementation detail:对于Cpython,id(x)是存储x的内存地址。

一个对象的类型决定了对象支持的操作(例如,“它有长度吗?”),还定义了该类型对象的可能值。type()函数的作用是:返回对象的类型(type本身就是一个对象)。与对象的标识一样,对象的类型也是不可更改的。

某些对象的值可以更改。值可以更改的对象称为可变的;值一旦创建就不可更改的对象称为不可变的。(包含对可变对象引用的不可变容器对象的值可以在此可变对象的值更改时更改;但是容器仍然被认为是不可变的,因为它包含的对象集合不能被更改。因此,不变性严格来说并不等同于拥有一个不变的值,它更为微妙。)对象的可变性由其类型决定;例如,数字、字符串和元组是不可变的,而字典和列表是可变的。

对象永远不会被显式销毁;但是,当它们无法访问时,可能会被垃圾收集。允许实现延迟垃圾收集或完全省略垃圾收集 —— 只要没有收集到仍然可访问的对象,那么如何实现垃圾收集则是实现质量的问题。

CPython implementation detail:CPython目前使用一种带有(可选的)延迟检测循环链接垃圾的引用计数方案,它在大多数对象变得不可访问时收集它们,但不能保证收集包含循环引用的垃圾。有关控制循环垃圾收集的信息,请参阅gc模块的文档。其它实现的行为不同,Cpython可能会改变。当对象变得不可访问时,不要依赖于对象的立即终结(因此您应该始终显式地关闭文件)。

请注意,使用实现的跟踪或调试工具可以使通常可收集的对象保持活动状态。还要注意,使用“try…except”语句捕捉异常可能会使对象保持活动状态。

有些对象包含对“外部”资源的引用,如打开的文件或窗口。可以理解,当对象被垃圾收集时,这些资源被释放,但是由于不能保证垃圾收集一定会发生,所以这些对象还提供了一种显式的方式来释放外部资源,通常是close()方法。强烈建议程序显式地关闭此类对象。“try…finally”语句和“with”语句提供了方便的方法。

有些对象包含对其它对象的引用;这些被称为容器(containers)。容器的例子有元组、列表和字典。引用是容器的值的一部分。在大多数情况下,当我们讨论容器的值时,我们暗示的是值,而不是所包含对象的标识;然而,当我们讨论容器的可变性时,仅暗示立即包含的对象的标识。因此,如果不可变容器(如tuple)包含对可变对象的引用,那么如果该可变对象被更改,则此不可变容器的值也会更改。

类型几乎影响对象行为的所有方面。甚至对象标识的重要性在某种意义上也受到影响:对于不可变类型,计算新值的操作实际上可能返回对任何具有相同类型和值的现有对象的引用,而对于可变对象则不允许这样做。例如,a = 1之后;b = 1, a和b可以引用值为1的对象,也可以不引用值为1的对象,这取决于实现,但是在c =[]之后;d =[],c和d保证引用两个不同的、惟一的、新创建的空列表。(注意,c = d =[]给c和d分配了相同的对象。)

3.2 The standard type hierarchy(标准类型层次结构)

下面是构建在Python中的类型列表。扩展模块(根据实现使用C、Java或其它语言编写)可以定义其它类型。Python的未来版本可能会将类型添加到类型层次结构中(例如,有理数、有效存储的整数数组等),尽管这些添加通常会通过标准库提供。

None

该类型只有一个值。只有一个对象具有这个值。此对象通过内置名称None访问。它用于表示在许多情况下没有值,例如,它是从没有显式返回任何值的函数返回的。它的真值是假的。

NotImplemented

该类型只有一个值。只有一个对象具有这个值。此对象通过内置的名称NotImplemented访问。如果数值方法和富比较方法未实现所提供操作数的操作,则应返回此值。(然后,解释器将尝试反射操作或其他一些回退,具体取决于运算符。)其真值为真。

Ellipsis(省略号)

该类型只有一个值。只有一个对象具有这个值。这个对象是通过文字或内置的名称 Ellipsis访问。其真值为真。

numbers.Number

它们由数值文字创建,并由算术运算符和算术内置函数作为结果返回。数值对象是不可变的;一旦创造了他们的值就不会改变。Python数字当然与数学数字密切相关,但受计算机中数字表示的限制。
Python区分整数、浮点数和复数:
          1. numbers.Integral

  这些表示整数(正整数和负整数)数学集合中的元素。
         整数有两种类型:

         Integers(int)

          这些表示无限范围内的数字,仅受可用(虚拟)内存的限制。为了进行移位和掩码操作,假设使用二进制表示,负数用2的补码的变体表示,这给人一种符号位向左侧延伸的无限字符串的错觉。

         Booleans (bool)

          这些代表了真值FalseTrue。表示值FalseTrue的两个对象是惟一的布尔对象。布尔类型是整数类型的子类型,在几乎所有上下文中,布尔值的行为都类似于值0和1,唯一的例外是,当转换为字符串时,分别返回字符串“False”“True”


          整数表示规则旨在对涉及负整数的移位和掩码操作给出最有意义的解释。

  2. numbers.Real (float)

       这些表示机器级双精度浮点数。对于可接受的溢出范围和处理,您完全取决于底层机器体系结构(以及C或Java实现)。Python不支持单精度浮点数;与Python中使用对象的开销相比,处理器和内存使用上的节省(通常是使用对象的原因)显得微不足道,因此没有理由使用两种浮点数使语言复杂化。

3. numbers.Complex (complex)

      它们将复数表示为一对机器级双精度浮点数。同样的注意事项也适用于浮点数。复数z的实部和虚部可以通过只读属性z.realz.imag来检索。

Sequences

这些表示由非负数索引的有限有序集。内置函数len()返回序列的项数。当序列长度为n时,索引集包含数字0,1,…,n-1。序列a的第i项由a[i]选择。
       序列还支持切片:a[i:j]选择索引为k的所有项,使i <= k < j。当用作表达式时,切片是同一类型的序列。这意味着索引集被重新编号,因此它从0开始。

有些序列还支持带有第三个“step”参数的“extended slicing”:a[i:j:k]选择索引为x的a的所有项,其中x = i + n*k, n >= 0, i <= x < j

序列是根据其可变性来区分的:

不可变序列

        不可变序列类型的对象一旦创建就不能更改。(如果对象包含对其他对象的引用,则这些其它对象可能是可变的,并且可能被更改;但是,不可变对象直接引用的对象集合不能更改。)

        以下类型是不可变序列:

         Strings

                字符串是表示Unicode代码点的值序列。在U+0000 - U+10FFFF范围内的所有代码点都可以用字符串表示。Python没有char类型;相反,字符串中的每个代码点都表示为长度为1的字符串对象。内置函数ord()将代码点从其字符串形式转换为0 - 10FFFF范围内的整数;chr()将范围为0 - 10FFFF的整数转换为相应长度为1的字符串对象。encode()可用于使用给定的文本编码将字符串转换为字节,而bytes.decode()可用于实现相反的目的。

        Tuples

               元组的项是任意的Python对象。两个或多个项的元组由逗号分隔的表达式列表组成。一个项目的元组(“单例”)可以通过在表达式中添加逗号来形成(表达式本身不创建元组,因为括号必须用于表达式的分组)。空元组可以由一对空括号组成。

       Bytes

               字节对象是一个不可变数组。这些项是8位字节,由0 <= x < 256范围内的整数表示。字节常量(如b'abc')和内置的Bytes()构造函数可用于创建Bytes对象。此外,字节对象可以通过decode()方法解码为字符串。

可变序列

       可变序列可以在创建之后更改。订阅和切片符号可以用作赋值和del (delete)语句的目标。

       目前有两种内在可变序列类型:

       Lists

             列表的项是任意Python对象。列表是通过在方括号中放置以逗号分隔的表达式列表来形成的。(注意,不需要特殊情况来形成长度为0或1的列表。)

      Byte Arrays

             bytearray对象是一个可变数组。它们是由内置的bytearray()构造函数创建的。除了可变(因此不可hash)之外,字节数组还提供了与不可变字节对象相同的接口和功能。

扩展模块array提供了一个可变序列类型的附加示例,collections模块也是如此。

Set types

这些表示无序的、有限的、惟一的、不可变的对象集。因此,它们不能被任何下标索引。但是,它们可以迭代,并且内置的函数len()返回集合中的项数。集合的常见用途是快速成员关系测试、从序列中删除重复项,以及计算数学运算,如交集(intersection)、并集(union)、差分(difference)和对称差分(symmetric difference)。
       对于集合元素,应用与字典键相同的不变性规则。注意,数值类型遵循数值比较的常规规则:如果两个数字比较相等(例如,1和1.0),则在一个集合中只能包含其中一个。
       目前有两种内在的集合类型:

Sets

     这些表示一个可变集。它们是由内置的set()构造函数创建的,之后可以通过几种方法(如add())进行修改。

Frozen sets

     它们表示一个不可变集。它们是由内置的frozenset()构造函数创建的。由于frozenset是不可变的和可哈希的,所以它可以再次用作另一个集合的元素或字典键。

Mappings

这些表示由任意索引集索引的有限对象集。下标符号a[k]从映射a中选择索引为k的项;这可以在表达式中使用,也可以作为赋值或del语句的目标。内置函数len()返回映射中的项数。

   当前只有一种内部映射类型:

Dictionaries

 这些表示由几乎任意值索引的有限对象集。键唯一不能接受的值类型是包含列表、字典或其它可变类型的值(这些值根据值而不是对象标识进行比较),原因是字典的有效实现需要键的哈希值保持不变。用于键的数字类型遵循数字比较的常规规则:如果两个数字比较相等(例如,1和1.0),那么它们可以互换使用,以索引相同的字典条目。

字典是可变的;它们可以通过{…}符号创建(请参阅Dictionary Displays一节)

扩展模块dbm.ndbm和dbm.gnu提供了映射类型的其它示例,collections模块也是如此。

Callable types

这些是可以应用函数调用操作(参见Calls部分)的类型:

User-defined functions

     用户定义的函数对象由函数定义创建(参见Function definitions部分)。应该使用包含与函数的形式参数列表相同数量的项的参数列表来调用它。

    特殊属性:

Attribute Meaning  
__doc__ 函数的文档字符串,如果不可用则为None;不被子类继承。 Writable
__name__ 函数名 Writable
__qualname__ 函数的限定名(qualified name)。版本3.3中的新功能。 Writable
__module__ 函数在其中定义的模块名,如果不可用则为None。 Writable
__defaults__ 一个元组,包含那些具有默认值的参数的默认参数值,如果没有参数具有默认值,则不包含默认值。 Writable
__code__ 表示已编译函数体的代码对象。 Writable
__globals__

对包含函数全局变量(定义函数的模块的全局命名空间)的字典的引用。

Read-only
__dict__ 支持任意函数属性的命名空间 Writable
__closure__ None或包含函数自由变量的绑定的单元元组。有关cell_contents属性的信息,请参见下面 Read-only
__annotations__ A dict containing annotations of parameters. The keys of the dict are the parameter names, and 'return' for the return annotation, if provided. Writable
__kwdefaults__ A dict containing defaults for keyword-only parameters. Writable

     大多数标记为“Writable”的属性检查赋值的类型。

python 数据模型(Data Model)_第2张图片

python 数据模型(Data Model)_第3张图片

      函数对象还支持获取和设置任意属性,例如,可以使用这些属性将元数据附加到函数。常规属性点符号用于获取和设置此类属性。注意,当前实现只支持用户定义函数上的函数属性。将来可能会支持内置函数上的函数属性。

     单元格对象具有cell_contents属性。这可以用来获取单元格的值,也可以用来设置值。

     函数定义的附加信息可以从其代码对象中检索;请参阅下面的内部类型描述。

Instance methods

      实例方法对象结合了类、类实例和任何可调用对象(通常是用户定义的函数)。

      特殊只读属性:__self__是类实例对象,_func__是函数对象;__doc__是方法的文档(与__func__.__doc__相同);__name__ 是方法名(与 __func__.__name__相同);方法定义所在的模块名为__module__,如果不可用,则为None。

      python 数据模型(Data Model)_第4张图片

python 数据模型(Data Model)_第5张图片

      方法还支持访问(但不支持设置)底层函数对象上的任意函数属性。

      当获取类的属性时(可能通过此类的实例),如果此属性是用户定义的函数对象或类方法对象,则可以创建用户定义的方法对象。

      当通过从类或实例中检索类方法对象来创建实例方法对象时,它的__self__属性是类本身,而它的_func__属性是类方法的底层函数对象。

python 数据模型(Data Model)_第6张图片

      当调用实例方法对象时,底层函数(__func__)被调用,并将类实例(__self__)插入参数列表前面。例如,当C是一个包含函数f()定义的类,而x是C的一个实例时,调用x.f(1)等价于调用C.f (x, 1)。

      当实例方法对象派生自类方法对象时,存储在__self__中的“类实例”实际上就是类本身,因此调用x.f(1)或C.f(1)就相当于调用f(C,1),其中f是底层函数。

      注意,每次从实例检索属性时,都会发生从函数对象到实例方法对象的转换。在某些情况下,有效的优化是将属性分配给局部变量并调用该局部变量。还要注意,这种转换只发生在用户定义的函数中;其它可调用对象(以及所有不可调用对象)无需转换即可检索。同样重要的是,作为类实例属性的用户定义函数不转换为绑定方法;只有当函数是类的属性时才会发生这种情况。

Generator functions

使用yield语句(参见The yield statement)的函数或方法称为生成器函数(generator function)。这样的函数在被调用时,总是返回一个迭代器对象,该对象可用于执行函数的主体语句:调用迭代器的iterator. __next__()方法将导致函数执行,直到它使用yield语句提供一个值。当函数执行return语句或结束时,将引发StopIteration异常,迭代器将到达要返回的值集的末尾。

Coroutine functions(协程函数)

使用async def定义的函数或方法称为协程函数。这样的函数在调用时返回一个协程对象。它可能包含await表达式,以及async with和async for语句。请参阅Coroutine Objects部分。

Asynchronous generator functions(异步生成器函数)

3.4 Coroutine(协程)

3.4.1. Awaitable Objects(可等待的对象)

awaitable对象通常实现一个__await__()方法。从async def函数返回的协程对象是可等待的。

注意:从用types.coroutine()或asyncio.coroutine()装饰的生成器返回的生成器迭代器对象也是可等待的,但它们没实现__await__()。

object.__await__(self)

             必须返回迭代器。应用于实现可等待的对象。例如,asyncio.Future实现此方法以与await表达式兼容。

3.4.2. Coroutine Objects(协程对象)

协程对象是可等待对象。可以通过 调用_await__()迭代结果 来控制协调程序的执行。当协同程序完成执行并返回时,迭代器将引发StopIteration,并且异常的value 属性将保存返回值。如果协程引发异常,则由迭代器传播该异常。协程不应该直接引发未处理的StopIteration异常。

协程还有下面列出的方法,它们类似于生成器的方法(请参阅 Generator-iterator方法)。然而,与生成器不同,协程不直接支持迭代。

coroutine.send(value)

       启动或恢复协同程序的执行。如果值为None,这相当于推进由__await__()返回的迭代器。如果值不是None,则此方法将委托给导致协程挂起的迭代器的send()方法。结果(返回值、StopIteration或其他异常)与在上面描述的__await__()返回值上迭代时的结果相同。

coroutine.throw(type[value[traceback]])

       在协同程序中引发指定的异常。该方法委托给导致协程挂起迭代器(如果迭代器有这样的方法)的throw()方法。否则,异常将在挂起点处引发。结果(返回值、StopIteration或其他异常)与在上面描述的_await__()返回值上迭代时的结果相同。如果异常没有在协程中捕获,它将传播回调用者。

coroutine.close()

       使协程自动清理并退出。如果协程被挂起,这个方法首先委托给导致协程挂起的迭代器的close()方法,如果它有这样的方法。然后,它会在悬浮点引发GeneratorExit,导致协同程序立即自我清理。最后,协程被标记为已经执行完毕,即使它从未启动过。

       当协程对象即将被销毁时,将使用上述过程自动关闭它们。

3.4.3. Asynchronous Iterators

异步迭代器(asynchronous iterator )可以在它的__anext__方法中调用异步代码。

异步迭代器可用于async for语句中。

object.__aiter__(self)

       必须返回异步迭代器(asynchronous iterator )对象。

object.__anext__(self)

      必须返回一个可等待的结果,从而得到迭代器的下一个值。迭代结束时应引发StopAsyncIteration错误。

异步可迭代对象的示例:

class Reader:
    async def readline(self):
        ...

    def __aiter__(self):
        return self

    async def __anext__(self):
        val = await self.readline()
        if val == b'':
            raise StopAsyncIteration
        return val

     

3.4.4. Asynchronous Context Managers(异步上下文管理器)

异步上下文管理器是一个上下文管理器,它能够在它的_aenter__和_aexit__方法中挂起执行。

异步上下文管理器可以在async with语句中使用。

object.__aenter__(self)

       这个方法在语义上类似于__enter__(),唯一的区别是它必须返回一个awaitable。

object.__aexit__(selfexc_typeexc_valuetraceback)

       这个方法在语义上类似于__exit__(),唯一的区别是它必须返回一个awaitable。

异步上下文管理器类的示例:

class AsyncContextManager:
    async def __aenter__(self):
        await log('entering context')

    async def __aexit__(self, exc_type, exc, tb):
        await log('exiting context')

 

 

 

 

 

 

 

 

你可能感兴趣的:(python 数据模型(Data Model))