Python类对象创建流程全解析:从new到__init__的高级理解

发布时间: 2024-10-01 07:13:34 阅读量: 6 订阅数: 7
![Python类对象创建流程全解析:从new到__init__的高级理解](https://plantpot.works/wp-content/uploads/2021/09/7396-1024x576.png) # 1. Python对象创建机制概述 Python作为一种面向对象的编程语言,其对象创建机制是整个语言机制中的核心部分。了解其底层的创建过程不仅可以帮助我们编写更加高效和优雅的代码,还可以让我们深入理解Python的工作原理。 Python对象的创建可以简单地分解为两个基本步骤:首先是内存的分配,其次是对对象的初始化。这一过程主要涉及两个内置方法:`__new__` 和 `__init__`。其中,`__new__` 负责创建对象并分配内存,而 `__init__` 则用来初始化对象的状态。虽然 `__init__` 方法在日常开发中更为常见,但理解 `__new__` 同样重要。 接下来的章节将对 `__new__` 和 `__init__` 进行深入分析,带领读者探索Python对象创建的幕后机制。我们将从这两个方法的基础知识开始,逐步揭示它们的工作原理和最佳实践,让读者能够更加得心应手地运用Python进行面向对象编程。 # 2. 深入理解__new__方法 ## 2.1 __new__方法的作用与原理 ### 2.1.1 对象分配与__new__方法的关系 在Python中,对象的创建首先涉及内存分配,而这一过程是由`__new__`方法控制的。`__new__`是一个类方法,负责分配一个新的实例对象,并返回该对象的引用。这一步发生在`__init__`方法之前,意味着即使对象被创建了,它也可能没有完全准备好,直到`__init__`方法完成其初始化过程。 `__new__`方法对于理解Python的继承关系和自定义对象创建行为至关重要。它通常接收至少一个参数`cls`,代表将要实例化的类。除此之外,它还可以接收`*args`和`**kwargs`作为额外的位置参数和关键字参数,以传递给类的构造函数。 理解`__new__`方法的工作原理,有助于深入掌握Python对象的生命周期,包括对象的创建、初始化,以及最终销毁的整个流程。 ### 2.1.2 __new__方法的调用时机 `__new__`方法的调用时机是在一个新对象实例被创建时。通常,这发生在我们通过类直接调用`__init__`方法时。但在某些特殊情况下,如继承、元类编程或使用工厂方法创建对象时,我们可能需要显式地重写或调用`__new__`方法。 在继承的情况下,子类的`__new__`方法会覆盖父类的`__new__`方法。如果子类中没有定义`__new__`方法,那么子类实例化时会调用父类的`__new__`方法。通过这种方式,开发者可以控制对象实例化的过程,并在其中加入自定义的逻辑。 ## 2.2 __new__方法的参数与返回值 ### 2.2.1 __new__方法的参数解析 `__new__`方法的参数列表设计为接收类本身和任意数量的位置参数和关键字参数。这提供了极大的灵活性,允许在创建新实例时传递不同的数据和配置。 - `cls`参数,它代表将要创建实例的类本身。 - `*args`参数,它是一个位置参数元组,包含创建新实例时传递的所有额外位置参数。 - `**kwargs`参数,它是一个字典,包含创建新实例时传递的所有额外关键字参数。 这些参数使得`__new__`方法能够接收任意数量的参数,从而创建更加灵活和复杂的对象结构。 ### 2.2.2 对象创建与__new__方法的返回值 `__new__`方法在对象创建过程中负责分配内存,并返回一个新的实例对象引用。这个返回值是一个实例化的对象,通常是一个类的实例。 如果`__new__`方法返回一个已经存在的实例对象,那么这个对象就会被重用,而不会再次调用`__init__`方法。这个特性可以用于实现单例模式,确保某个类只创建一个实例。 需要注意的是,如果`__new__`方法返回的不是一个类的实例,那么它应当返回`cls.__new__(cls, *args, **kwargs)`调用的结果,否则会出现类型不匹配的错误。 ## 2.3 自定义__new__方法的实践 ### 2.3.1 理解继承中的__new__方法 在继承中,子类的`__new__`方法会覆盖父类的`__new__`方法,这允许子类在创建实例前修改类的构造行为。这在设计需要对基类进行重大修改的子类时非常有用。 自定义的`__new__`方法通常会首先调用父类的`__new__`方法来保持正常的实例化逻辑,然后在此基础上添加自定义的行为,例如增加额外的属性或者改变对象的状态。 ### 2.3.2 实现单例模式的__new__方法 单例模式确保一个类只有一个实例存在。通过`__new__`方法可以有效地实现单例模式。在这个模式下,如果一个实例已经存在,那么每次请求创建一个新实例时,`__new__`方法都会返回已存在的实例。 实现单例模式的代码如下: ```python class Singleton: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) return cls._instance # 使用Singleton创建对象,可以确保对象的唯一性 obj1 = Singleton() obj2 = Singleton() # obj1和obj2是同一个对象 print(obj1 is obj2) # 输出True ``` 在上述代码中,`Singleton`类的`__new__`方法会检查一个实例是否已经存在。如果不存在,则使用`super()`调用父类的`__new__`方法创建一个新实例,并将其存储在类变量`_instance`中。如果实例已经存在,则直接返回`_instance`。 通过这种方法,无论调用多少次类的构造器,都只返回同一实例,从而实现单例模式。 # 3. __init__方法的全面剖析 ## 3.1 __init__方法的作用与生命周期 ### 3.1.1 初始化方法__init__与对象状态 在Python中,每当创建一个新实例时,`__init__`方法都会被自动调用,它用于初始化对象的状态。初始化方法是类定义中一个特殊的方法,其名称前后的双下划线表示这是一个魔术方法,用于在创建对象后立即对对象进行设置。它通常包括将传入的参数赋值给对象实例变量,或者执行一些必要的初始化步骤。 ```python class Person: def __init__(self, name, age): self.name = name self.age = age def introduce(self): return f"Hello, my name is {self.name} and I am {self.age} years old." # 创建一个Person实例 person = Person('Alice', 30) # 使用introduce方法 print(person.introduce()) ``` 在上面的例子中,`__init__`方法接收了`name`和`age`两个参数,并将它们分别赋值给实例变量`self.name`和`self.age`。之后,这些变量在`introduce`方法中被使用,以提供个人介绍。 ### 3.1.2 __init__方法的调用时机和频率 `__init__`方法仅在对象实例化时被调用一次,这与`__new__`方法不同,后者在每次实例化时都会被调用。这意味着`__init__`方法对于设置对象在实例化之后的初始状态至关重要。需要注意的是,尽管`__init__`方法是设置对象初始状态的常规方法,但它并不返回对象本身,而是返回`None`,因此不应该对`__init__`方法的返回值进行任何假设。 ```python class Person: def __init__(self): print("This is __init__") person ```
corwn 最低0.47元/天 解锁专栏
送3个月
点击查看下一篇
profit 百万级 高质量VIP文章无限畅学
profit 千万级 优质资源任意下载
profit C知道 免费提问 ( 生成式Al产品 )

相关推荐

import http.client from html.parser import HTMLParser import argparse from concurrent.futures import ThreadPoolExecutor import multiprocessing.pool prefix = "save/" readed_path = multiprocessing.Manager().list() cur_path = multiprocessing.Manager().list() new_path = multiprocessing.Manager().list() lock = multiprocessing.Lock() class MyHttpParser(HTMLParser): def __init__(self): HTMLParser.__init__(self) self.tag = [] self.href = "" self.txt = "" def handle_starttag(self, tag, attrs): self.tag.append(tag) # print("start tag in list :" + str(self.tag)) if tag == "a": for att in attrs: if att[0] == 'href': self.href = att[1] def handle_endtag(self, tag): if tag == "a" and len(self.tag) > 2 and self.tag[-2] == "div": print("in div, link txt is %s ." % self.txt) print("in div, link url is %s ." % self.href) lock.acquire() if not self.href in readed_path: readed_path.append(self.href) new_path.append(self.href) # print("end tag in list :" + str(self.tag)) lock.release() self.tag.pop(-1) def handle_data(self, data): if len(self.tag) >= 1 and self.tag[-1] == "a": self.txt = data def LoadHtml(path, file_path): if len(file_path) == 0: file_path = "/" conn = http.client.HTTPConnection(path) try: conn.request("GET", file_path) response = conn.getresponse() print(response.status, response.reason, response.version) data = response.read().decode("utf-8") if response.status == 301: data = response.getheader("Location") lock.acquire() new_path.append(data) lock.release() data = "" #print(data) conn.close() return data except Exception as e: print(e.args) def ParseArgs(): # 初始化解析器 parser = argparse.ArgumentParser() # 定义参数 parser.add_argument("-p", "--path", help="域名") parser.add_argument("-d", "--deep", type=int, help="递归深度") # 解析 args = parser.parse_args() return args def formatPath(path): path = path.removeprefix("https://") path = path.removeprefix("http://") path = path.removeprefix("//") return path def doWork(path): path = formatPath(path) m = path.find("/") if m == -1: m = len(path) data = LoadHtml(path[:m], path[m:]) with open(prefix + path[:m] + ".html", "w+", encoding="utf-8") as f: f.write(data) parse.feed(data) def work(deep,maxdeep): if deep > maxdeep: return args = ParseArgs() cur_path.append(formatPath(args.path)) readed_path.append(formatPath(args.path)) parse = MyHttpParser() e = multiprocessing.Pool(4) for i in range(args.deep): size = len(cur_path) e.map(doWork,cur_path) cur_path[:]=[] for p in new_path: cur_path.append(p) new_path[:]=[] print(i)优化此代码能在windows下运行

李_涛

知名公司架构师
拥有多年在大型科技公司的工作经验,曾在多个大厂担任技术主管和架构师一职。擅长设计和开发高效稳定的后端系统,熟练掌握多种后端开发语言和框架,包括Java、Python、Spring、Django等。精通关系型数据库和NoSQL数据库的设计和优化,能够有效地处理海量数据和复杂查询。
专栏简介
本专栏深入探讨了 Python 中的 `new` 库文件,重点关注面向对象编程中对象的创建机制。它涵盖了以下主题: * 类和对象的创建过程 * `new` 和 `__new__` 方法之间的区别 * `new` 方法在继承中的覆盖策略 * 元类和 `new` 方法的交互 * 利用 `new` 方法优化对象创建 * 不可变对象的创建 * `new` 和 `__init__` 方法的交互 * `new` 方法的正确使用方法 * 使用 `new` 实现单例模式 * `new` 方法在并发环境中的表现 * `new` 方法在封装性中的应用 本专栏旨在帮助 Python 开发人员深入理解 `new` 库文件,并掌握其在对象创建、内存管理和并发编程中的高级应用。
最低0.47元/天 解锁专栏
送3个月
百万级 高质量VIP文章无限畅学
千万级 优质资源任意下载
C知道 免费提问 ( 生成式Al产品 )

最新推荐

Peewee模型序列化与反序列化:构建前后端分离应用

![Peewee模型序列化与反序列化:构建前后端分离应用](https://cdnblog.dataweave.com/wp-content/uploads/2015/08/python.jpg) # 1. Peewee简介与前后端分离架构 ## 1.1 Peewee简介 Peewee是一个小巧且易于使用的Python ORM(对象关系映射器),它允许开发者通过简单的代码操作数据库,极大地提升了数据库操作的便捷性和代码的可读性。Peewee提供了一组简洁的API,支持多种数据库后端,如SQLite、MySQL和PostgreSQL,特别适合轻量级项目和小型API开发。 ## 1.2 前后端

YAML与JSON在Python中的终极对比:选对数据格式赢未来

![YAML与JSON在Python中的终极对比:选对数据格式赢未来](https://img-blog.csdnimg.cn/7d3f20d15e13480d823d4eeaaeb17a87.png) # 1. YAML与JSON简介及其在Python中的应用 YAML(YAML Ain't Markup Language)和JSON(JavaScript Object Notation)是两种流行的轻量级数据序列化格式。它们广泛应用于配置文件、网络传输以及数据存储中。在Python中,这两种格式不仅可以通过标准库轻易解析,还提供了灵活的数据处理能力。JSON由于其广泛的应用在Web开发中

Tornado日志管理实战:应用状态的记录与监控技巧

![Tornado日志管理实战:应用状态的记录与监控技巧](https://yqfile.alicdn.com/9b410119c1307c45b32a17b7ceb0db955696982d.png) # 1. Tornado日志管理概述 Tornado是一个强大的Python Web框架和异步网络库,广泛应用于高并发的网络服务和实时数据处理。日志管理是Tornado应用中不可或缺的一部分,它不仅记录了应用程序的运行轨迹,还帮助开发者定位问题、分析性能以及满足安全合规要求。 本章将概述Tornado日志系统的基本组成和日志管理的重要性。日志记录是调试程序和监控应用状态的有力工具。它能够记

性能提升秘籍:C++ Redistributable优化应用的5种方法

![性能提升秘籍:C++ Redistributable优化应用的5种方法](https://fastbitlab.com/wp-content/uploads/2022/11/Figure-2-7-1024x472.png) # 1. 理解C++ Redistributable的作用 在本章,我们将对C++ Redistributable的含义和它在应用程序中扮演的关键角色进行探讨。首先,我们将介绍C++ Redistributable是什么,它如何帮助软件运行,以及为什么它是IT行业不可或缺的一部分。随后,我们会深入探讨C++ Redistributable如何作为运行时组件,为软件提供

从Laravel到Python:Eloquent经验迁移到SQLAlchemy的实践指南

![从Laravel到Python:Eloquent经验迁移到SQLAlchemy的实践指南](https://learningprogramming.net/wp-content/uploads/laravel/product-table-structure.jpg) # 1. Laravel Eloquent ORM简介 ## 1.1 Eloquent的诞生背景 Laravel Eloquent ORM 是 Laravel 框架提供的一个对象关系映射器(Object-Relational Mapping, ORM)。其允许开发者通过 PHP 类和方法与数据库进行交云,无需直接处理 SQL

【快速上手与进阶】:Python调试秘籍,pdb使用技巧全解析

![【快速上手与进阶】:Python调试秘籍,pdb使用技巧全解析](https://hackernoon.imgix.net/images/5unChxTmteXA0Tg5iBqQvBnMK492-vda3ure.jpeg) # 1. Python调试与pdb简介 Python的调试工作是开发者在软件开发过程中的关键环节之一。调试可帮助开发者理解程序的执行流程,发现并修复代码中的错误(bug)。而pdb是Python提供的一个内置的交互式源代码调试工具。它允许开发者在程序中的特定位置暂停执行,逐行执行代码,并检查程序中的状态,这对于定位复杂的程序问题尤为有效。 pdb的主要优势在于它的灵

Twisted框架IOCP深入探讨:实现高效IO操作的秘诀

![Twisted框架IOCP深入探讨:实现高效IO操作的秘诀](https://files.realpython.com/media/Threading.3eef48da829e.png) # 1. Twisted框架与IOCP概述 在计算机网络领域中,I/O模型的设计对于程序的效率和性能有着决定性的影响。IOCP(I/O完成端口)是一种高度优化的I/O模型,特别适合于高并发网络服务场景。它最早由Microsoft引入,用于提高Windows平台下网络服务的可扩展性和性能。而Twisted是一个广泛使用的Python网络框架,其独特的事件驱动模型使开发者能够轻松构建高性能的网络应用。 #

C++源码阅读技巧:深入解读开源项目的关键之道

![C++源码阅读技巧:深入解读开源项目的关键之道](https://cdn.prod.website-files.com/5f02f2ca454c471870e42fe3/5f8f0af008bad7d860435afd_Blog%205.png) # 1. C++源码阅读的重要性与准备 C++作为一种高性能的编程语言,在软件开发领域占据了举足轻重的地位。阅读C++源码不仅可以帮助开发者深入理解语言特性和库的设计,还能提升编程技能和设计思维。在开始源码阅读之前,重要的是要做好充分的准备工作,这包括熟悉C++的基础知识、选择合适的阅读工具、以及设置一个利于深入研究的环境。 准备工作涉及到多

XML-RPC与IoT:探索xmlrpclib库在物联网应用中的无限可能

![XML-RPC与IoT:探索xmlrpclib库在物联网应用中的无限可能](https://www.anirudhsethi.in/blog/wp-content/uploads/2018/09/xmlrpc_install-1024x526.png) # 1. XML-RPC与物联网的基础概念 随着物联网(IoT)技术的蓬勃发展,各种设备和服务之间的通信标准和协议成为技术发展的重要组成部分。XML-RPC,一种使用XML编码其调用的远程过程调用(RPC)协议,通过标准化的数据格式和HTTP传输,实现了跨平台和语言的远程方法调用。物联网设备多样性和异构网络环境,对通信协议提出了更高的要求

【Visual Studio C++图形界面开发实战:】MFC与WinForms快速上手指南

![visual studio c++](https://www.hitsubscribe.com/wp-content/uploads/2019/01/SuccessfulXUnitTests-1024x569.png) # 1. Visual Studio C++图形界面开发概览 ## 1.1 开发环境配置与准备 在深入了解Visual Studio C++图形界面开发前,首先需要确保开发环境配置正确。这涉及到安装Visual Studio集成开发环境(IDE),并配置好所需的C++编译器和工具集。此外,理解开发工具与工作空间(Workspaces)和项目(Projects)的差异对于