当前位置: 首页 > news >正文

Python-__init__函数

__init__ 是 Python 语言规定好的一个特殊函数

它在 Python 中有一个专门的分类,叫做魔术方法(Magic Methods)“Dunder 方法” (Dunder 是 “Double Underscore” 双下划线的缩写)。

它的“特殊”主要体现在以下三个方面:

1. 特殊的命名:__...__

__init__ 这个名字是 Python 规定死的。

  • 它以两个下划线开头,并以两个下划线结尾。
  • 在 Python 中,所有具有这种 __名字__ 格式的函数都是“魔术方法”。它们都是 Python 预先定义好的,用于在特定时机自动执行某些操作。
  • 你不能随便起一个自己的 __my_func__ 名字并期望它有魔术功能。你只能重写 (override) Python 已经定义好的这些魔术方法,比如 __init____str__ (用于 print(obj) 时) 或 __add__ (用于 obj1 + obj2 时)。

2. 特殊的调用时机:自动调用

这是 __init__ 最特殊的地方。

  • 永远不需要手动调用 __init__ 函数。
  • 当你通过“调用类名”来创建对象(实例化)时,Python 会自动为你调用它。
# 1. 定义 "节点" 类
class TrieNode(object):def __init__(self):# 节点应该包含这两个属性self.children = {}self.isEndOfWord = False# 2. 定义 "树" 类 (这是你的模板)
class Trie(object):def __init__(self):# "树" 的构造函数: 创建一个 "节点" 作为根self.root = TrieNode() def insert(self, word):""":type word: str:rtype: None"""# 1. 从根节点开始node = self.rootfor char in word:if char not in node.children:# 2. 创建一个 *新的 TrieNode*node.children[char] = TrieNode()# 3. 移动到子节点node = node.children[char]# 4. 标记单词结尾node.isEndOfWord = Truedef search(self, word):""":type word: str:rtype: bool"""node = self.rootfor char in word:if char not in node.children:return Falsenode = node.children[char]return node.isEndOfWorddef startsWith(self, prefix):""":type prefix: str:rtype: bool"""node = self.rootfor char in prefix:if char not in node.children:return Falsenode = node.children[char]return True

我们来分解一下 trie_node = TrieNode() 这一行代码:

  1. 构造 (Creation):Python 先调用一个(隐藏的)__new__ 方法,在内存中创建了一个空白TrieNode 对象。
  2. 初始化 (Initialization):Python 立刻、自动地调用 __init__ 方法,并把你创建的这个空白对象作为第一个参数(self)传进去。
  3. 赋值 (Assignment)__init__ 函数执行完毕(即 self.children = {}self.isEndOfWord = False 完成后),这个已经初始化好的对象才被赋值给 trie_node 变量。

所以,__init__ 的特殊之处在于它是一个“钩子”(hook) 函数:你不需要关心它何时被调用,你只需要在 class 里定义好它,Python 就会在创建对象的正确时机自动触发它。

3. 特殊的角色:初始化器 (Initializer)

__init__唯一角色就是“初始化”。

  • 它不负责创建对象(那是 __new__ 的工作)。
  • 它负责**“装修”**这个刚刚被创建出来的空白对象,给它装上它一出生就该有的属性(比如 self.root)。

__init__ 的用法非常固定和清晰。它几乎只用来做一件事设置对象(self)的初始属性(也叫“实例变量”)

通俗地说,__init__ 就是这个对象“出生”时必须运行的设置程序。你在这里定义:“凡是这个类的对象,一出生就必须有这些东西。”


“一般用法”的三种常见模式

这里有三个最常见的例子,从简单到复杂:

模式一:最简单的用法(如 TrieNode

目的: 对象一出生,就给它设置好“空”的默认属性。

TrieNode 的例子中,我们不需要在创建时给它任何信息。但每个节点必须有一个 children 字典和 isEndOfWord 标志。

class TrieNode:def __init__(self):# 1. 你没有给任何参数# 2. 你在 self (对象自己) 身上 "装上" 初始属性print("一个新节点被创建了!")self.children = {}  # 它天生就有一个空的 children 字典self.isEndOfWord = False # 它天生就不是单词结尾# 当你调用...
new_node = TrieNode()
# ...Python 自动为你调用 __init__
# 输出: "一个新节点被创建了!"# 现在 new_node 已经有了这两个属性:
print(new_node.children)      # 输出: {}
print(new_node.isEndOfWord) # 输出: False

模式二:最常见的用法(如 Person

目的: 创建对象时,接收外部参数,并用这些参数来设置属性。

假设你要创建一个 Person 类。一个人“出生”时,总得有个名字和年龄吧。

class Person:# `name` 和 `age` 是你创建对象时必须提供的参数def __init__(self, name, age):print(f"一个叫 {name} 的人被创建了!")# 把接收到的参数 `name` 赋值给 self 的 `name` 属性self.name = name# 把接收到的参数 `age` 赋值给 self 的 `age` 属性self.age = ageself.is_sleeping = False # 也可以设置一个默认值# 当你调用...
# ("Alice", 30) 会被传递给 __init__ 的 (name, age)
p1 = Person("Alice", 30)
# 输出: "一个叫 Alice 的人被创建了!"# p1 对象现在有了这些属性:
print(p1.name) # 输出: Alice
print(p1.age)  # 输出: 30

模式三:嵌套用法(如 Trie

目的: 对象在初始化时,创建其他类的对象作为自己的属性。

这就是你的 Trie (树) 的例子。Trie 树“出生”时,它不需要外部给它 children 字典(它自己不是节点),但它必须有一个 root 属性,而这个 root 是另一个对象(一个 TrieNode)。

class Trie:def __init__(self):# 1. 你没有给任何参数# 2. 你在 self (树) 身上 "装上" root 属性# 3. 这个属性的值, 是通过创建另一个类的实例 (TrieNode) 得到的print("一棵新的前缀树被创建了!")self.root = TrieNode() # 当你调用...
trie_tree = Trie()
# 输出: "一棵新的前缀树被创建了!"
# (在创建 Trie 的过程中, 它内部又自动调用了 TrieNode 的 __init__, 
# 所以你可能还会看到 "一个新节点被创建了!")# trie_tree 对象现在有了 root 属性:
print(trie_tree.root) # 输出: <__main__.TrieNode object at 0x....>
print(trie_tree.root.children) # 输出: {}

总结:__init__ 的“使用规则”

你应该做的(Do):

  1. 定义实例属性__init__首要工作就是定义 self.attribute = ...
  2. 接收创建参数:把 MyClass(arg1, arg2) 传进来的 arg1arg2,通过 __init__(self, arg1, arg2) 接收,并存到 self.attribute1 = arg1 中。
  3. 执行一次性设置:如果对象一创建就需要执行某个动作(比如 self.setup_database_connection()),可以放在 __init__ 里。

应该做的(Don’t):

  1. return 任何东西__init__ 必须返回 None。Python 会自动处理它,你绝对不要在 __init__ 里写 return selfreturn True
  2. 放复杂的逻辑__init__ 应该非常快。它只是用来“设置属性”的,不要在里面放需要 10 秒钟才能算完的复杂计算。那些应该单独写成一个方法(比如 obj.calculate_complex_stuff())。

我们来“扮演”一下 Python 解释器,看看当你写 node.children[char] = __init__() 时它会怎么想。

(我们暂时假装你代码里的 node = self.root 这一行是 node = self,这样它至少能开始运行,以便我们能分析到你问的这一行。)


场景: 你调用 trie.insert("app")

  1. node 被设为 self (即 trie 对象)。
  2. 循环开始,char'a'
  3. if 'a' not in node.children: (假设 trie.children 是空的),条件为 True
  4. Python 运行到你的关键代码行node.children['a'] = __init__()
  5. Python 停住了。它会想:“__init__ 是什么?你让我调用一个叫 __init__ 的函数,但我不知道它在哪里。”

我一开始犯的错误:
在这里插入图片描述

为什么会这样?(两个核心错误)

我写的 __init__ 是一个方法 (Method),它“属于” Trie 类。它不是一个可以随处调用的全局函数 (Global Function)(像 print() 那样)。

错误 1:NameError(语法错误)

当只写 __init__() 时,Python 会在当前(insert 方法的)局部作用域和全局作用域里寻找一个独立的、名叫 __init__ 的函数

它根本找不到。

它会立即崩溃,并抛出 NameError: name '__init__' is not defined

错误 2:“那如果我改成 self.__init__() 呢?”(逻辑错误)

这是一个非常好的假设!我们来看看如果代码是 node.children['a'] = self.__init__(),会发生什么:

  1. Python:“哦!我知道 self.__init__ 是什么!它就是 Trie 类的那个初始化函数。好的,我来替你调用它!”
  2. self.__init__() 开始执行。
  3. self.children = {} <-- 灾难! trie刚刚把自己的 children 字典(里面可能已经有东西了)重置为了一个空字典!
  4. self.isEndOfWord = False
  5. self.__init__ 函数执行完毕。
  6. __init__ 函数的返回值是什么?根据 Python 规定,它必须返回 None
  7. Python 回到 insert 方法,继续执行赋值:node.children['a'] = None

最终的结果是:

  1. 搞砸了 trie 树(重置了它的 children)。
  2. node.children 字典里存了一个 None
  3. 根本没有创造出一个新节点

总结:想要的 vs 写的

  • 想要做的: “请为我创建一个全新的节点对象 (Create a new TrieNode instance)。”
  • 实际写的: __init__() (这会导致 NameError)
  • 可能想写的: self.__init__() (这会重新初始化当前的 Trie并返回 None)

正确的“命令” 不是调用 __init__
正确的“命令”是调用类名

node.children[char] = TrieNode()

这个命令才是告诉 Python:“请运行 TrieNode 类的完整创建流程__new__ + __init__),并把那个全新的对象返回给我。”

http://www.dtcms.com/a/520895.html

相关文章:

  • 沈阳网站维护公司网站建设财务怎么入账
  • JavaEE:知识总结(一)
  • 各家高性能MCU的内置Flash逐渐走向MRAM之路,关于嵌入式 MRAM 的性能和能效
  • Leetcode 35
  • GPIO口输出
  • 专教做美食的网站胶州哪里有做网站的
  • 企业网站制作 徐州网站设计原则的历史
  • 隐私保护与数据安全合规(十三)
  • 2025年高真空共晶炉排名
  • 网站做转链接违反版权吗wordpress页面不显示子类
  • 5.3类的构造方法
  • 视频监控系统原理与计量
  • 蓝桥杯高校新生编程赛第一场题解——Java
  • JavaScript 的优势和劣势是什么?
  • 鸿蒙Next的Camera Kit:开启全场景智慧影像开发新纪元
  • 软件开发包含网站开发吗搭建网站成本
  • asp.net 微网站开发教程比较大的建站公司
  • h5游戏免费下载:小猪飞飞
  • 基于单片机的档案库房漏水检测报警labview上位机系统设计
  • 网站开发图标汕头网站建设seo外包
  • DeepSeek-OCR:光学Token:长上下文建模的范式转变
  • Windows 11 24H2内核堆栈保护:系统安全新盾牌
  • 自定义组件(移动端下拉多选)中使用 v-model
  • Android 14 系统启动流程深度解析:AVB流程
  • 阳春做网站0735郴州招聘信息网
  • 营销型网站建设申请域名网站翻页动画效果
  • NGINX架构特点和实现原理
  • 基于单片机的两路PWM信号输出及频率占空比相位差调节系统
  • uniapp三端影视源码苹果cms自动采集电影视频网站源码前端源码带VIP
  • 算法学习笔记-贪心算法总结