如何理解Python的一切都是对象?

引言

我学过多门编程语言,却变得越来越迷惑。我们知道C语言,每个变量都需要声明变量类型,在函数调用的时候也必须保证参数类型一致。而python 的变量不需要声明类型,且甚至不许要提前声明,python极大的降低了程序开发的门槛(牺牲性能换来的)。本文着重解决2个问题:

  • Python如何实现不需要声明数据类型
  • python语言本身体现了哪些设计模式?

本文借由第一个问题探究python语言设计的底层实现,借由第二个问题探究python语言设计时的高层设计模式思想。

一、Python

Python是使用C语言编写的,同时也包含了很多用C语言编写的标准库。Python使用C语言的主要原因之一是因为C语言具有高效性和可移植性。Python的开源代码托管在GitHub上,其仓库地址为:https://github.com/python/cpython/

1. Python语言和C语言有什么不同?

  • 语法:Python采用缩进风格,使用冒号来表示代码块,而C语言采用大括号来表示代码块。

  • 类型:Python是动态类型语言各种变量可以在运行时动态绑定不同的类型;而C语言是静态类型语言,变量类型在编译期间就确定了。

  • 自动内存管理:Python自动进行内存管理,程序员不需要手动管理内存;而C语言需要手动进行内存管理,包括内存分配和释放。

  • 编译和解释:C语言需要先编译成二进制机器码,再执行;而Python是解释型语言,直接由解释器解释执行。

  • 应用场景:C语言适合编写操作系统、编译器等系统级应用;而Python适合用于数据分析、Web开发、人工智能等领域。

总体来说,Python是一门简单易学、高效率、高可读性的语言,适合于快速开发原型以及处理数据;而C语言是一门底层语言,可以直接操作硬件和内存,适合于编写高性能、底层系统级的程序。

2. Python如何实现不需要声明类型?

Python是一种动态类型语言,变量在使用之前不需要先声明数据类型,主要是通过以下方式进行实现的:

  1. 类型推断:Python在运行时通过分析代码语法和变量的初值等信息来推断其类型。这符合Python的“自然”哲学,同时也方便开发者理解和维护代码。

  2. 动态申请内存:Python在申请内存的时候,是根据变量类型来动态分配内存的。在赋值时如果值改变了类型,Python会自动释放原有内存并重新申请所需要的内存。

  3. 引用计数:Python使用引用计数来追踪变量的生命周期,每当一个对象被引用时其引用计数加1,每当一个对象失去一个引用时其引用计数减1。当引用计数为0时,Python将释放该对象占用的内存空间。

  4. 对象模型:Python的一切都是对象,代码的执行就是对象之间的交互和操作。因此,在Python中变量所引用的是一个对象,而不是一个内存地址,这样也就可以避免了其他语言中可能会出现的指针错误、内存泄漏等问题。

综上所述,Python通过类型推断、动态申请内存、引用计数以及对象模型等方式,实现了变量不需要声明类型的特性。

3. 如何理解Python的一切都是对象?

在Python中,“一切皆为对象”是一种重要的概念。这意味着,Python中的每个元素——包括数字、字符串、数据结构、函数、模块等等——都被视为一个对象。“对象”是一个抽象的概念,它包含了数据和行为。数据可以是各种类型的值,行为则是对象可以执行的动作或操作。在Python中,每个对象都有一个类型,这个类型定义了对象能够执行哪些操作和支持哪些方法。

在Python中,所有类都继承自一个名为object的基类。这意味着,如果在Python中定义一个类但没有指定其任何超类,那么它将自动成为object的子类。object类包含了一些特殊方法(也称为“魔术方法”),这些方法对于对象的操作非常重要。例如,__init__() 方法用于对象的初始化,__str__() 方法用于将对象转换为字符串,__eq__() 方法用于比较两个对象是否相等等。

例1 执行如下代码:if(i==0)

在C语言中,上述代码将被编译为一条条件跳转指令(如JZJE),该指令会检查变量i的值是否等于0,如果相等则跳转到if语句内部执行,否则跳过if语句。

在Python中,上述代码会被解释器解析为一条布尔比较操作 i==0,然后根据比较的结果决定是否执行if语句内部的代码块。Python解释器会对 i0 进行对象的比较操作,即执行i.__eq__(0) 根据比较结果决定是否执行if语句内的代码块。

例2 字符串拼接

C语言中底层实现比较原始,字符串是以字符数组的形式存在的。C语言中使用strcat()方法将字符数组进行合并操作,合并后的字符串直接存放在原字符数组中,不会单独开辟一个新的内存空间。在C语言中,需要自己实现一个字符串的合并函数,而不能直接使用运算符重载来实现字符串相加。

python语言中可以通过str = str1+str2直接进行字符串的拼接。使用的是运算符重载,即当执行 str1 + str2 时,Python 实际上会执行 str1.__add__(str2) 的操作,而不是简单的把两个字符串拼接起来,底层封装了增加新的内存、拷贝旧字符串、拼接新字符串、删除旧字符串等实现逻辑。代码实现上比较简单,但是由于字符串是不可变对象,每次相加时都会创建新的对象,会带来额外的内存开销。

下面是 Python 中 object 类的常用魔术方法(magic method)或特殊方法(special method)及其功能的总结:

魔术方法 功能
__class__ 调用 type() 函数访问对象的类属性
__delattr__(self, name) 定义当试图删除一个对象的属性时要调用的方法
__dir__(self) 定义如何响应独立于对象之外的 dir() 内置函数调用
__doc__ 显示对象的文档字符串
__eq__(self, other) 支持等于运算符(==)
__format__(self, format) 定义格式化对象时调用的方法,使用字符串的 format() 方法
__ge__(self, other) 支持大于等于运算符(>=)
__getattribute__(self, name) 定义当用户试图访问一个对象的属性时要调用的方法
__gt__(self, other) 支持大于运算符(>)
__hash__(self) 返回哈希值(必须是整数)
__init__(self[, args...]) 构造器,用于在创建对象时进行初始化操作
__init_subclass__() 在此类(而不是实例)的子类被创建时被调用
__le__(self, other) 支持小于等于运算符(<=)
__lt__(self, other) 支持小于运算符(<)
__ne__(self, other) 支持不等于运算符(!=)
__new__(cls[, args...]) 用于创建对象并返回该对象的方法
__reduce__(self) 用于为 pickle 模块提供支持
__reduce_ex__(self, protocol) 同上,但支持更多的协议
__repr__(self) 用于为调试服务的字符串表示
__setattr__(self, name, value) 定义当用户试图设置对象的属性时要调用的方法
__sizeof__(self) 返回对象占用的内存字节数
__str__(self) 用户获取对象的字符串表示
__subclasshook__(cls, subclass) 在子类继承时调用,用于检查子类是否合法

需要注意的是,这些方法并不是全部都需要在我们自己的类中重载实现,而是根据实际的需要进行选择性实现。同时,Python中还有其他许多内置函数和内置类型,它们都有其特殊的用法和常用的魔术方法。

4.int类型

我们以整数类型 int 为例继续解释python的底层机制,int 继承自 object 类,并新增了一些内置函数用于整数类型的操作:

  • __add__(self, other):用于实现整数加法,相当于 self + other
  • __sub__(self, other):用于实现整数减法,相当于 self - other
  • __mul__(self, other):用于实现整数乘法,相当于 self * other
  • __truediv__(self, other):用于实现整数除法,相当于 self / other
  • __floordiv__(self, other):用于实现整数整除,相当于 self // other
  • __mod__(self, other):用于实现整数取模运算,相当于 self % other
  • __pow__(self, other[, modulo]):用于实现整数幂运算,相当于 self ** other
  • __lshift__(self, other):用于实现按位左移运算,相当于 self << other
  • __rshift__(self, other):用于实现按位右移运算,相当于 self >> other
  • __and__(self, other):用于实现按位与运算,相当于 self & other
  • __or__(self, other):用于实现按位或运算,相当于 self | other
  • __xor__(self, other):用于实现按位异或运算,相当于 self ^ other
  • __invert__(self):用于实现按位取反运算,相当于 ~self
  • __index__(self):将该整数转化为索引形式,以支持一些内置函数和方法,如 listtupledict 等。

这些内置函数使得整数对象可以支持不同的运算和操作,使得我们可以灵活地处理整数数据。

5.元类(metaclass)

Python 元类(metaclass)实际上就是用于创建类的类,它可以控制类的创建行为和属性,从而实现更高级别的面向对象编程。可以理解为类对象object的’‘父类’'。在 Python 中,元类是非常重要的概念,可以通过以下属性来控制类的创建和行为:

方法名 描述
__new__(cls, name, bases, attrs, **kwargs) 用于创建并返回一个新的类对象
__init__(self, name, bases, attrs, **kwargs) 用于初始化类对象,并可以对类对象的属性和方法进行修改
__call__(self, *args, **kwargs) 用于自定义类对象实例化过程。包括实例的创建和初始化过程。它可以实现许多高级的面向对象编程功能,比如单例模式、对象池
__getattribute__(self, name) 用于获取对象的属性,元类可重载此方法来实现属性访问控制和管理
__setattr__(self, name, value) 用于设置对象的属性,元类可重载此方法来实现更细粒度的属性设置控制和管理
__getattr__(self, name) 用于获取对象的不存在的属性时,需要调用的函数,元类可重载此方法来实现属性的默认值、惰性计算等

6.Type()函数创建类

在 Python 内部实现中,object 类在 C 语言中定义,其数据结构实际上是一个 C 结构体(struct),其中储存了对象的类型信息和一些特殊的标志位。这个 C 结构体被称为 Python 对象头(object header),其定义如下:

typedef struct _object {
    
    
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

其中,_PyObject_HEAD_EXTRA 表示一些额外的头部信息,ob_refcnt 表示对象的引用计数,ob_type 指向对象所属的类型信息,即对象的类对象。

在 Python 中,所有对象的类对象都是通过 type() 函数来创建的,包括 object 类本身。当我们定义一个新的类时,实际上是通过 type() 函数动态创建了一个新的类对象,并将其与类的名称进行绑定,从而创造出一个新的类。例如:

class MyClass:
    pass

当执行以上代码时,Python 解释器会自动调用 type() 函数来创建一个名为 MyClass 的新类对象,然后将其绑定到一个变量名 MyClass 上,从而使得 MyClass 成为一个可用的类。可以使用 type() 函数来验证对象所属的类对象,例如:

obj = MyClass()
print(type(obj))  # <class '__main__.MyClass'>
print(type(MyClass))  # <class 'type'>
print(type(object))  # <class 'type'>

从输出结果可以看出,objMyClass 类对象的一个实例,而 MyClass 类本身是由 type 类创建的,而 type 类本身又是由 object 类创建的,这也说明了 object 类是 Python 中最基础的类。

猜你喜欢

转载自blog.csdn.net/weixin_41099712/article/details/129974326