新闻详情

新闻详情

首页 / 资讯中心 / 详情

Python __init__ 完全解析:从初始化方法到对象生命周期

发布时间:2026/10/2 4:14:41来源:尧图网络
Python __init__ 完全解析:从初始化方法到对象生命周期
1. 先把它“名分”捋清楚init到底是不是构造函数每次面试 Python 岗位我几乎都会问一个问题“__init__是构造函数吗”十个人里有八个点头剩下两个犹豫说“应该是吧”。这个答案说对也对说错也错。__init__在中文社区里被叫了这么多年“构造函数”但实际上它在 Python 里的定位是初始化方法真正负责“构造”实例的是藏在后面的__new__。举个例子你会看到这样的写法class User: def __init__(self, name): self.name name u User(张三)看起来像是User(张三)调用了__init__完成了对象创建。但其实完整的流程是Python 先调用User.__new__(User, 张三)创建出一个空壳实例然后才把张三传给__init__去填充属性。__new__负责“从无到有”__init__负责“从有到好”。那为什么几乎所有教程都在教“__init__就是构造函数”因为 99% 的日常编码里你不需要重写__new__你只需要在__init__里给实例「上户口」——设置属性、建立不变量、做参数校验。所以大家约定俗成地把__init__当成“构造”来用这在工程沟通上没问题但在遇到真正需要控制实例创建的高级场景时分不清这两个阶段就会卡住。再顺手说一个高频疑惑双下划线开头的__init__是不是“私有方法”不是。Python 里的双下划线有自己的特殊含义但它不是私有化的意思。这个我放到后面单独讲因为很多人就是在这里开始把名字搞混的。1.1 双下划线不是私有的代名词而是“名称改写”的信号Python 没有真正意义上的 private 关键字约定俗成用单个下划线_name表示“内部使用外部别碰”。而双下划线开头的__name实际上触发的是name mangling名称改写当你在class A里写了self.__xPython 解释器会把属性名悄悄改写成_A__x。所以__init__这个“神奇”的名字本质上是解释器预留的一个钩子你定义它实例化时解释器就自动调用它。它不是私有方法而是“协议方法”——Python 里的__xxx__双端双下划线都属于这类协议钩子比如__str__、__repr__、__len__。__init__只是这套协议里最常见的一个。理解这一点很多连带问题就通了为什么__init__必须叫这个名字因为解释器认这个名字你写成__initialize__它就不认了实例化后啥也不干类照常创建但属性全无程序后续跑起来全是AttributeError。为什么不能把__init__写成普通方法再手动调用能但那就丢了“实例化时自动执行”的语义而且u.__init__(李四)这种做法会把初始化逻辑和对象生命周期绑定得乱七八糟代码可读性差到极点队友看了想打人。为什么有的类不写__init__也能正常工作因为基类object提供了一个默认的空__init__你定义的类会继承它调用时什么都不初始化实例还是能创建出来。这也是为什么“可以不写”但要清楚“不写等于没有做任何初始状态设置”。所以第一课把__init__当成“实例化时的自动初始化钩子”来理解而不是“构造函数”。这样你在看源码、看框架时才会意识到“原来这个类在创建实例时自动做了这些事”而不是觉得它只是一个普通的类方法。2. 实例化的完整链路new与init如何分工合作顺着刚才的话题我们正式把“一次实例化”从头到尾拆开看。很多人写了好几年 Python也没完整看过这条链路上每一步发生了什么但这恰恰是理解__init__的关键——因为它的运行时机、参数来源、返回值约束全由这条链路决定。比如class User: def __init__(self, name, age): self.name name self.age age当你写下u User(张三, 18)时解释器实际执行了这些步骤调用__new__方法传入类本身User以及参数(张三, 18)object.__new__在内存中分配一块空间返回一个新的空实例。检查__new__返回的实例是不是User的实例。如果不是__init__不会被调用实例化结果就是__new__返回的那个对象。如果确实是User的实例解释器自动调用__init__(instance, 张三, 18)把步骤 1 创建的实例作为self传入剩下的参数原样传递。__init__执行完属性赋值逻辑后这个新实例被返回给变量u。这就像你去车管所上牌照__new__相当于从生产线开下来一辆空车车架号已生成__init__相当于给你这辆车上户、装内饰、贴膜。哪怕你在__init__里写了再复杂的逻辑车的“物理存在”在__init__之前就已经确立了。2.1 为什么init不能有返回值接着上面的链路__init__有一个非常容易被忽略的约束它不能返回非 None 的值。如果你在__init__里写了return self或者return 123运行时会直接抛TypeError: __init__() should return None。为什么因为实例创建和返回的职责已经由__new__完成了__init__的定位就是“只做初始化不做生产”。你可以把__new__看成生产车间的下料机把__init__看成质检和装配工位——装配工位不能把车再退回给生产线它只能往车里装东西。工程上这件事的意义在于当你看到一个人的代码里__init__有返回值时几乎可以断定他刚从 Java 或 C 转过来还在按“构造函数必须返回对象”的习惯写。Python 里你强行让它返回东西解释器直接教你做人。所以如果你的初始化逻辑里需要“创建失败了要不要返回一个默认对象”正确的做法是放在__new__里做或者干脆在__init__抛出异常——因为__init__抛异常__new__创建的对象会被立刻丢弃实例化过程中止调用方拿到的是异常而不是一个半成品对象。我见过一个坑有人在__init__里做网络请求请求超时后except了一下然后return None想表达“初始化失败”结果 Python 直接TypeError。正确的姿势是在__init__里让异常继续抛或者用raise转成自定义异常这样调用方才能明确感知失败。2.2 self 参数到底是谁传的再说说self。很多初学者把self当成魔法关键字其实它是约定俗成的名字你可以写成this、obj、whatever解释器都不在乎。关键在于self是“实例化时由解释器自动传入的实例对象本身”。在调用User(张三, 18)的时候等价于obj User.__new__(User, 张三, 18) User.__init__(obj, 张三, 18) # 在这里 obj 被当作 self 传了进去而当你拿到一个已有实例u调用u.get_info()时等价于User.get_info(u)那个u又被当作第一个参数传进方法。这就是为什么实例方法定义时必须写第一个参数接收它——你写的每个参数都是从第二个位置开始对应调用时传的参数。稍微绕一点的是类方法和静态方法classmethod传的是类而不是实例参数名习惯叫clsstaticmethod则什么都不自动传。前者适合写“通过类来构造实例”的备选构造器比如class User: def __init__(self, name, age): self.name name self.age age classmethod def from_dict(cls, data): return cls(data[name], data[age])这样你可以u User.from_dict({name: 张三, age: 18})而from_dict内部调用cls(...)时cls就是User接着又走一遍__init__。这是非常实用的扩展初始化入口的模式后面讲边界场景时会再遇到。3. 初始化时的参数处理默认值、校验、可变对象这三个坑把__init__的基本语法捋清后就该聊实际写代码时最磨人的部分参数。很多人写__init__时只考虑“把参数赋给属性”结果项目大型化之后各种诡异 bug 全是从初始化参数的处理细节里冒出来的。3.1 默认参数值为可变对象这个坑十年了还有人在踩class ShoppingCart: def __init__(self, items[]): self.items items一眼看上去没问题但实际上这个写法有严重缺陷Python 的默认参数值是在函数定义时计算并保存一次的这个[]是同一个列表对象。如果你创建两个购物车cart1 ShoppingCart() cart1.items.append(apple) cart2 ShoppingCart() print(cart2.items) # 输出 [apple]第二个购物车居然继承了第一个购物车的内容。原因就是它们共享了同一个默认列表。正确的写法是class ShoppingCart: def __init__(self, itemsNone): self.items items if items is not None else []或者更明确一点class ShoppingCart: def __init__(self, itemsNone): self.items list(items) if items is not None else []用list(items)拷贝一次还能防止调用方把外部列表传进来后后续外部修改影响类内部状态。这个知识点的本质是默认值只求值一次可变对象作为默认值等于所有实例共享同一块数据。在我看过的代码评审里这个错出现频率不低于“忘了写 self”。3.2 参数校验放在init里是性价比最高的防御有人把参数校验散落到业务代码里比如每次用到age时都判断一次它是不是 int、是不是大于 0。我个人的习惯是只要这个参数是一个对象的固有属性校验就该在__init__里做。为什么因为对象一旦创建出来它的状态应该从一开始就是合法的。等到使用时再校验错误发生的位置离源头很远排查成本高好几倍。class User: def __init__(self, name, age): if not isinstance(name, str) or not name.strip(): raise ValueError(name 必须是非空字符串) if not isinstance(age, int) or age 0: raise ValueError(age 必须是正整数) self.name name self.age age这样写任何一个非法数据都在对象出生的瞬间被拦截。哪怕项目里有十个地方创建User都能享受同样的校验不用在每个调用点重复防御。当然校验也不能走极端。如果参数本身就是合理范围内的可选值不必做过于严苛的类型检查因为 Python 的核心哲学之一是鸭子类型。我的经验是对“会导致后续代码崩溃”的条件要做校验对“传入什么类型都行只要支持某某接口”的情况留到实际使用时由 AttributeError 自然暴露。3.3 别在init里做太多事这节说的不是语法问题而是设计问题。见过不少人的__init__里塞了几百行读配置、连数据库、发请求、算报表、预热缓存……结果就是实例化一个对象慢得像启动一个服务而且难以测试——每次创建对象都得连带真实的外部依赖。关键原则是__init__负责“让对象处于可用状态”而不是“把对象需要的所有资源全部拉齐”。如何平衡我一般这样拆分纯数据赋值、格式转换、基本校验放__init__这些都是廉价且确定性的操作。昂贵的资源获取网络、数据库连接、大文件加载要么延迟到首次使用时再懒加载要么提供单独的connect()、load()之类方法让调用方显式触发。依赖外部配置才能确定的属性尽量提供默认值或通过类方法、工厂函数注入避免在__init__里偷偷读取全局配置。这样做的直接收益是单元测试里你能极快地创建对象、替换依赖而不是被__init__里的副作用拖住。4. 经典八股super().init() 到底在干嘛凡是写过继承的人几乎都在子类的__init__里见过这一行class Manager(User): def __init__(self, name, age, department): super().__init__(name, age) self.department department好多人就是“背口诀”子类初始化要调 super。但说不清为什么一旦碰到多重继承、菱形继承就彻底晕了。这一节把这件事讲透。super()返回的不是父类而是一个“代理对象”它的作用是按 MRO方法解析顺序找到下一个应该被调用的类方法。在单继承链里它差不多就是“父类的初始化方法”在多重继承里它负责按 C3 线性化算法确定的顺序把初始化调用依次传递下去。4.1 不调 super().init() 会怎么样先看一个不调 super 的例子class User: def __init__(self, name): self.name name class Manager(User): def __init__(self, name, department): self.department department m Manager(张三, 技术部) print(m.name) # AttributeError: Manager object has no attribute name不调 super父类的__init__永远不会执行name属性压根不存在。这是最直接的后果。但也有一种微妙情况如果父类没有定义__init__子类不调 super 也没什么影响因为默认继承的是object.__init__它本身不初始化任何东西。工程上我还遇到过一个隐蔽问题父类__init__里做了统计埋点或缓存注册子类忘了调 super导致父类的副作用逻辑被悄悄跳过。这种 bug 不会立刻报错但会在观测数据里缺一块排查起来非常难受。所以只要父类定义了__init__且你想要它的初始化语义就老老实实调super().__init__(...)。4.2 带参数的继承初始化与坐标对齐实际的麻烦出现在父类参数很多时。比如class Base: def __init__(self, a, b, c): self.a a self.b b self.c c class Child(Base): def __init__(self, d, a, b, c): super().__init__(a, b, c) self.d d这种写法的可读性还算能接受但一旦层级多了参数顺序就是灾难。更稳的写法是使用关键字参数尤其在多重继承里class Child(Base): def __init__(self, d, **kwargs): super().__init__(**kwargs) self.d d父类用关键字参数接收自身需要的值子类只要把不认识的都往上传。配合**kwargs即使 MRO 链上的类各自需要不同参数也能在super()调用链里按名称准确匹配而不是赌位置。不过我要提醒一点**kwargs虽然灵活但会让__init__的签名失去自文档能力。调用方看不出应该传什么参数。我的建议是只在真正的多重继承协作场景使用它单继承场景还是明确写出形参更友好。代码可读性比省几行字重要得多。4.3 菱形继承下的 super 调用链一个反直觉的例子看这个经典模型class A: def __init__(self): print(A init) super().__init__() class B(A): def __init__(self): print(B init) super().__init__() class C(A): def __init__(self): print(C init) super().__init__() class D(B, C): def __init__(self): print(D init) super().__init__() d D()反直觉的地方在于D 实例化时super()不是从 D 直接跳到“父类 B”而是沿着 MRO 依次调用每个类的__init__并且每个__init__里的super()都会把控制权交给 MRO 上的下一个类。最终打印顺序是D init B init C init A initC 在 B 之后、A 之前被调用这跟直觉上的“B 继承 A、C 继承 A”完全不一致。如果你在代码里假设“我只调了 B 的初始化它内部自然会把 A 也初始化完”在菱形继承里就会失灵——B 的super()根本不通往 A而是通往 C。所以处理多重继承下的__init__时我的经验是三条能不用多重继承就不用了组合优于继承。非用不可每个参与类的__init__都要保持super()调用的连续性避免中途断链。初始化参数的传递用关键字参数并用**kwargs兜底确保 MRO 链上每个类都能拿到需要的值。5. 当常规初始化不够用时new、set_name与init_subclass前面讲的都是__init__的“常规操作”但实际项目里总会出现一些场景目标不是“给实例填属性”而是“控制实例的创建方式”“拦截属性的初始化时机”“在子类定义时动态改行为”。这一节聊几个与__init__配套的进阶钩子帮助你把“从生到养”的最后一公里打通。5.1 用new实现单例模式为什么不重写init单例模式是面试高频题也是实践里常常误用的模式。Python 实现单例核心思路是让__new__返回同一个实例从而让__init__被重复调用同一个对象。class Singleton: _instance None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance super().__new__(cls) return cls._instance def __init__(self, value): self.value value这里有个容易被忽略的细节每次调用Singleton(xxx)__new__返回的都是同一个实例但__init__依然会被执行——因为解释器的规则是“只要__new__返回的实例是cls类型就调用__init__再初始化一次”。所以上面这个单例的 value 每次都会被覆盖成最新值而不是“只有第一次创建时设置值”。如果你的行为预期是“首次初始化后就不再被改动”那必须自己加标记class Singleton: _instance None _initialized False def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance super().__new__(cls) return cls._instance def __init__(self, value): if Singleton._initialized: return Singleton._initialized True self.value value坦率讲单例在现代 Python 工程里使用频率已经很低了依赖注入、模块级常量通常能取代它。但如果你出于历史原因需要维护单例代码一定要把这个“__init__会重复执行”的机制记清楚否则大概率会写出一个“值永远被最后一次覆盖”的假单例。5.2 描述符里的set_name与初始化时机__set_name__是 Python 3.6 加入的钩子它的触发时机是“类定义完成后解释器自动调用描述符的__set_name__方法把描述符所在的类名和属性名传给它”。看个实际例子class PositiveNumber: def __set_name__(self, owner, name): self.name name def __get__(self, obj, objtypeNone): if obj is None: return self return obj.__dict__.get(self.name, 0) def __set__(self, obj, value): if value 0: raise ValueError(必须是正数) obj.__dict__[self.name] value class Order: price PositiveNumber() count PositiveNumber()这里PositiveNumber()没有在__init__里接收字段名而是靠__set_name__自动获知自己被赋给了Order.price和Order.count。这套机制的价值在于描述符对象在类定义阶段就能拿到自己的属性名省去了“必须在__init__里手工传 name”的繁琐写法。如果你在实现 ORM 字段、数据校验器、属性托管之类的基础设施__set_name__几乎是标配。要注意__set_name__只在类创建时调用一次它不属于实例初始化流程。所以它适合做“元信息登记”不适合做“实例级别的状态设置”。这两者的区别在很多框架代码里很容易混淆建议读源码时留意。5.3init_subclass在子类诞生时干预__init_subclass__是另一个和初始化相关但不在实例维度上的钩子。它在“一个类被定义且该类的父类拥有__init_subclass__”时被调用。典型使用场景是父类要求所有子类必须指定某个类属性否则报错。class PluginBase: registry {} def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) if not getattr(cls, plugin_name, None): raise TypeError(f{cls.__name__} 必须定义 plugin_name) PluginBase.registry[cls.plugin_name] cls这相当于在子类的“出生时刻”做了一次登记和检查。和__init__对比它管的是类对象本身而不是类创建出来的实例。插件系统、规则引擎、命令分发这类框架很适合用这个机制实现自动注册省去手工维护注册表的麻烦。看到这里你会发现一个规律Python 的初始化体系并不是只有__init__一个点而是分布在“类创建”“实例创建”“属性访问”多个生命周期节点上。__init__是日常接触最频繁的节点但真正深入项目时这些相邻钩子常常会成为“把方案做优雅”的关键。6. 当init变得很啰嗦几种常用的写法重构与选择最后来聊一个偏工程口味的话题__init__写多了之后你会发现自己总在重复一些模式比如“参数太多”“赋值代码机械”“属性校验逻辑占了一半篇幅”。这个章节我会分享几种在实践中常用的简化方案和取舍心得。6.1 参数过多从“位置参数堆砌”到“数据类/工厂函数”一个类的__init__如果有七八个以上参数调用方记顺序就会很痛苦。最直接的改进是把参数改成关键字参数并给出默认值class ReportConfig: def __init__(self, title, author, dateNone, templatedefault, output_dir./dist, verboseFalse, encodingutf-8): ...这样调用就可以写成ReportConfig(月报, author张三, verboseTrue)不需要记住每个参数的顺序。但仍有一个问题调用方的可读性依然不够好尤其是这些参数之间没有强关联时不如直接用一个字典或专门的数据类。Python 3.7 之后的dataclasses模块是这类场景的利器from dataclasses import dataclass dataclass class ReportConfig: title: str author: str date: str template: str default output_dir: str ./dist verbose: bool False encoding: str utf-8dataclass会自动生成__init__、__repr__、__eq__等方法省去手写机械化的self.title title赋值。更重要的是它把“数据类的初始化语义”用类型注解表达出来一眼就能看懂这个对象装的是什么。如果你需要额外的校验逻辑还可以定义__post_init__它会在自动生成的__init__的末尾被调用dataclass class ReportConfig: title: str output_dir: str ./dist def __post_init__(self): if not self.title.strip(): raise ValueError(title 不能为空)实际上__post_init__就是dataclass情境下的“补充__init__逻辑”的钩子。我的经验是普通领域对象、配置对象、DTO能上dataclass就上省下的代码量非常可观而需要复杂继承结构、需要手动控制实例创建流程的类才保留手写__init__。6.2 备选构造器的命名与心智负担有些对象可以从多种途径创建从数据库行、从 JSON、从表单、从默认配置。把这些逻辑全塞进一个__init__会让初始化方法变成一个巨型分发器。更清晰的方案是用类方法提供备选构造器class Order: def __init__(self, order_id, user_id, items, total): self.order_id order_id self.user_id user_id self.items items self.total total classmethod def from_dict(cls, data): return cls( order_iddata[order_id], user_iddata[user_id], items[Item(**i) for i in data[items]], totaldata[total], ) classmethod def create_empty(cls, user_id): return cls(order_id, user_iduser_id, items[], total0)这样Order.from_dict(...)明确表达“从字典构建”Order.create_empty(...)表达“创建空订单”而__init__本身保持纯粹——只接收最终状态数据。它不关心这些数据是怎么来的只确保对象出生即合法。这种模式在需要对接多种数据源的项目里几乎是必须的否则__init__会慢慢长成缝合怪。命名上也有一些小讲究from_dict、from_json、from_row、load、create_default都是常见后缀。保持命名习惯统一团队协作时猜代码的成本会低很多。6.3 一个“养成系”类的完整示例把前面所有内容串起来最后用一个稍微完整的示例把前面涉及的__init__初始化、参数校验、备选构造器、继承协作、__post_init__这些知识点揉在一起。场景是一个配置类既支持从环境变量加载也支持直接传入参数还要在初始化时校验值。from dataclasses import dataclass, field from typing import Optional dataclass class AppConfig: app_name: str debug: bool False max_workers: int 4 extra: dict field(default_factorydict) def __post_init__(self): if not self.app_name.strip(): raise ValueError(app_name 不能为空) if self.max_workers 0: raise ValueError(max_workers 必须大于 0) classmethod def from_env(cls, envNone): env env or {} return cls( app_nameenv.get(APP_NAME, default), debugenv.get(DEBUG, false).lower() in (1, true, yes), max_workersint(env.get(MAX_WORKERS, 4)), ) classmethod def create_default(cls): return cls(app_namedefault)这里from_env返回的cls(...)会走一遍自动生成的__init__也就是先赋值属性再执行__post_init__做校验。一旦遇到非法值异常在对象出生时立刻抛出调用方不会拿到一个“看起来能用但实际不合法”的配置对象。如果你把extra这种字典字段写成field(default_factorydict)还能规避前面提到的可变默认值坑。注意dataclass里不能写extra: dict {}这种字面默认值因为它会在类定义阶段就创建同一个字典和普通__init__的可变默认值问题是同一根源。这个例子做下来你会发现“从生到养”的核心思路在工程上落地为几个动作出生时把属性定下来__init__或dataclass自动生成的构造器出生时做体检__post_init__或__init__里的校验逻辑提供不同的出生通道类方法构造器、工厂函数复杂场景下接管出生过程__new__控制实例创建类本身的“出生”也需要初始化时__init_subclass__、__set_name__。7. 经验沉淀代码评审里最常见的初始化问题清单文章最后我把它浓缩成一份可以在团队里直接用的检查清单。这些是我自己在代码评审时几乎每次都会过一遍的点也是新手最容易忽视的地方。7.1 一眼就能看出的问题可变默认值def __init__(self, items[])必须改成None 在方法体内创建新容器。__init__有非 None 返回值直接违反解释器约束必然报错。忘记调用super().__init__()子类定义的属性掩盖了父类需要初始化的字段运行期才爆AttributeError。参数命名与父类不一致在单继承里容易造成“子类传了参数但父类收不到”的错觉排查成本很高。在__init__里做耗时网络请求实例化慢、测试困难、依赖外部环境。7.2 需要结合业务理解的问题校验逻辑到底放在__init__还是放在使用时我倾向于前移但如果是性能敏感且高频创建对象的地方要评估校验成本。一个类是否适合用dataclass自动生成__init__如果它有复杂的继承、需要自定义__new__、需要与已有框架的构造协议配合还是手写更稳妥。备选构造器是否造成了“多个入口、行为不一致”的问题需要保证每个构造器最终都收敛到同一个__init__的约束逻辑上。**kwargs的滥用包裹了太多未知参数会让 IDE 补全失效建议只用在确实需要透传的多重继承场景。7.3 最后的小建议我个人在实际项目中的体会是__init__不是一个需要背很多技巧的知识点而是一个“你如何理解对象生命周期”的窗口。当你把它看成一个“实例出生后的第一次初始化时机”时很多关于应该做什么、不该做什么的判断都会变得顺理成章。如果你现在正被某个__init__相关的 bug 折磨不妨按这个顺序自查一遍第一这个类是否正确地调用了父类初始化第二是否有可变默认值被多个实例共享第三实例化失败时__init__抛出的异常是不是足够明确第四__init__里做的事情是否超出了“让对象可用的最小状态”的范围。多数情况下问题就出在这四个环节里。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

CRM数据库表设计实战:从线索到合同的高可用建模 2026/10/2 8:29:14

CRM数据库表设计实战:从线索到合同的高可用建模

简介:本资源是一份面向数据库设计初学者与CRM系统开发者的《CRM客户关系管理系统数据库表设计需求规格说明书》,聚焦企业级权限管理、销售机会跟踪与客户信息建模等核心场景。文档完整定义了10张关键数据表(含角色、菜单、权限、用户、销售机…

阅读更多 →
食品饮料工厂数字化MES:批次追溯与配方下发的落地实践 2026/10/2 8:29:14

食品饮料工厂数字化MES:批次追溯与配方下发的落地实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
PyCharm警告shadows name from outer scope:Python变量遮蔽原理与五种解决技巧 2026/10/2 8:29:07

PyCharm警告shadows name from outer scope:Python变量遮蔽原理与五种解决技巧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
开源油藏模拟器OPM/Flow实战:从安装到与Eclipse对比 2026/10/2 8:29:01

开源油藏模拟器OPM/Flow实战:从安装到与Eclipse对比

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
双系统无人机仿真环境,及途中容易遇到的问题解决方法 2026/10/2 8:29:01

双系统无人机仿真环境,及途中容易遇到的问题解决方法

简介:在电脑配置较为一般的情况下,通过安装双系统来配置无人机仿真环境, 该帖子主要是讲核心框架和在运行途中常见报错具体进行流程请自行用AI搜索,推荐AI千问 注: 在安装之前记得买一个8个G以上的U盘 写该帖子的原因:…

阅读更多 →
JVM ZGC 垃圾回收器深度解析 2026/10/2 8:28:54

JVM ZGC 垃圾回收器深度解析

JVM ZGC 垃圾回收器深度解析ZGC(Z Garbage Collector)是 Oracle 于 JDK 11 引入(实验特性)、JDK 15 转正(JEP 377)、JDK 21 实现分代(JEP 439)的新一代回收器。它的核心承诺只有一条…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉