90%的程序员都没搞懂的编程基础概念,你中了几个?
2026/5/14 3:05:08 网站建设 项目流程

文章目录

    • 前言
    • 一、Python dict vs OrderedDict:都有序了,为啥还没被淘汰?
      • 1.1 先搞清楚:普通dict的“有序”到底是什么意思?
      • 1.2 这四个核心区别,90%的人都不知道
        • 区别1:相等性判断完全不同
        • 区别2:OrderedDict支持移动元素位置
        • 区别3:OrderedDict支持弹出两端元素
        • 区别4:内存开销不同
      • 1.3 2026年了,什么时候该用OrderedDict?
    • 二、TCP三次握手:背了百遍,为啥还是答不上“为什么不是两次”?
      • 2.1 先看一个最通俗的类比:打电话
      • 2.2 为什么不是四次?
      • 2.3 2026年了,这个知识点还有用吗?
    • 三、过拟合与欠拟合:AI训练准确率99%,上线直接崩?
      • 3.1 最通俗的类比:考试背答案 vs 理解知识点
      • 3.2 本质:模型复杂度与数据量的匹配
      • 3.3 2026年了,如何解决过拟合与欠拟合?
        • 解决欠拟合的方法:
        • 解决过拟合的方法:
    • 四、编译 vs 构建:代码写得溜,一编译就报错?
      • 4.1 先搞清楚:编译和构建到底有什么区别?
      • 4.2 为什么构建工具这么复杂?
      • 4.3 2026年了,有哪些好用的构建工具?
    • 五、异常处理:不是try-except包一切,而是精准捕获
      • 5.1 异常处理的本质:不是掩盖错误,而是处理错误
      • 5.2 2026年了,异常处理的最佳实践
    • 写在最后

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

前言

兄弟们,先问个扎心的问题:你写代码多少年了?是不是觉得自己CRUD写得炉火纯青,接口调得行云流水,AI插件一装,一天能生成100个功能,感觉自己马上就要晋升架构师了?结果一到面试,面试官一句“Python 3.7之后普通dict已经有序了,那OrderedDict还有存在的必要吗?”,你当场就懵了?

再问一个:你是不是背了无数遍TCP三次握手、四次挥手的八股文,面试的时候能一字不差地背出SYN、ACK、FIN的序号变化,结果面试官问“为啥是三次不是两次?四次行不行?”,你支支吾吾半天,只能说“书上就是这么写的”?

还有更扎心的:你花了一下午搭好一个神经网络,训练的时候看着准确率一路飙到99%,损失值跌到接近0,心里美滋滋觉得自己马上就要跻身AI大神行列了,结果一上线用真实用户数据一测,准确率直接腰斩到50%,甚至还不如瞎蒙的准,当场傻眼?

我在AI行业摸爬滚打了22年,面过的候选人没有一千也有八百,最近这两年尤其是2026年,这种情况见得太多了。很多程序员张口就是大模型、智能体、云原生,结果连最基础的编程概念都没搞懂。他们觉得“基础没用,能干活就行”,觉得“AI都能写代码了,学基础干嘛”,但恰恰是这些看似没用的基础,决定了你能走多远。

GPT-5.4确实能一天生成100个没有bug的CRUD接口,但它不会帮你排查线上的端口耗尽问题;AI插件确实能自动生成CMake脚本,但它不会告诉你为什么链接会失败;大模型微调工具确实能一键训练模型,但它不会告诉你为什么模型过拟合得这么严重。

今天我就来盘点一下,90%的程序员都没搞懂的5个编程基础概念,看看你中了几个。

一、Python dict vs OrderedDict:都有序了,为啥还没被淘汰?

先从最常用的Python字典说起。我敢打赌,至少有80%写了3年以上Python的程序员,被问到“Python 3.7之后普通dict已经有序了,那OrderedDict还有存在的必要吗?”这个问题时,都会当场卡壳。

很多人心里都会嘀咕:对啊,都有序了,这俩货不就是一回事吗?还有啥区别?我见过太多做AI算法、后端开发的老哥,天天跟字典打交道,结果连这个最基础的问题都答不上来。

1.1 先搞清楚:普通dict的“有序”到底是什么意思?

很多人以为Python 3.7之后的普通dict和OrderedDict完全一样,都是严格按照插入顺序保存元素,这其实是一个巨大的误区。

我给大家打个通俗的比方:普通dict就像是一个“宽松的排队系统”,它会记住大家的排队顺序,但是如果有人中途插队,它不会管;而OrderedDict则是一个“严格的排队系统”,不仅记住排队顺序,还会严格执行排队规则,任何插队行为都会被记录,而且还支持“把某个人移到队首/队尾”、“弹出队首/队尾元素”这些操作。

具体来说,普通dict的“有序”只是指迭代顺序和插入顺序一致,仅此而已。它并没有为“顺序”提供任何额外的操作支持,也没有把“顺序”作为相等性判断的依据。

1.2 这四个核心区别,90%的人都不知道

区别1:相等性判断完全不同

这是最容易被忽略的一点。对于普通dict来说,只要两个字典包含的键值对完全相同,不管插入顺序如何,它们就是相等的。

dict1={"a":1,"b":2}dict2={"b":2,"a":1}print(dict1==dict2)# 输出 True

但对于OrderedDict来说,插入顺序也是相等性判断的一部分。只有当两个OrderedDict的键值对完全相同,并且插入顺序也完全一致时,它们才是相等的。

fromcollectionsimportOrderedDict od1=OrderedDict({"a":1,"b":2})od2=OrderedDict({"b":2,"a":1})print(od1==od2)# 输出 False

这个区别在什么场景下会用到呢?比如你需要比较两个配置文件是否完全一致,或者需要对字典进行哈希处理(比如作为字典的键),这时候插入顺序就非常重要了。

区别2:OrderedDict支持移动元素位置

OrderedDict提供了move_to_end()方法,可以将指定的键移动到字典的开头或结尾,这是普通dict完全没有的功能。

od=OrderedDict({"a":1,"b":2,"c":3})od.move_to_end("b")# 将"b"移动到末尾print(od)# 输出 OrderedDict([('a', 1), ('c', 3), ('b', 2)])od.move_to_end("b",last=False)# 将"b"移动到开头print(od)# 输出 OrderedDict([('b', 2), ('a', 1), ('c', 3)])

这个功能在实现LRU(最近最少使用)缓存时简直是神器。2026年了,很多人还在自己手写LRU缓存,其实用OrderedDict只需要几行代码就能搞定。

区别3:OrderedDict支持弹出两端元素

普通dict只能通过pop(key)弹出指定键的元素,或者通过popitem()弹出最后插入的元素。而OrderedDict的popitem()方法支持一个last参数,可以选择弹出队首还是队尾的元素。

od=OrderedDict({"a":1,"b":2,"c":3})print(od.popitem(last=False))# 弹出队首元素 ('a', 1)print(od.popitem(last=True))# 弹出队尾元素 ('c', 3)

这个功能在实现FIFO(先进先出)队列时非常有用,比用列表实现的队列效率高得多。

区别4:内存开销不同

虽然普通dict在Python 3.7之后也有序了,但它的内存开销比OrderedDict要小一些。这是因为OrderedDict为了支持顺序操作,维护了一个双向链表,而普通dict只是在哈希表的每个节点中记录了插入顺序。

不过在2026年的今天,内存已经不是什么大问题了,除非你要创建几百万个字典,否则这点内存差异完全可以忽略不计。

1.3 2026年了,什么时候该用OrderedDict?

很多人觉得既然普通dict已经有序了,那OrderedDict就可以被淘汰了,这其实是大错特错。在以下这些场景中,OrderedDict依然是不可替代的:

  1. 实现LRU缓存:这是OrderedDict最经典的使用场景,没有之一。
  2. 需要严格的顺序相等性判断:比如配置文件比较、数据序列化。
  3. 需要频繁移动元素位置:比如优先级队列、任务调度。
  4. 需要弹出两端元素:比如FIFO队列、滑动窗口。

二、TCP三次握手:背了百遍,为啥还是答不上“为什么不是两次”?

接下来我们说说计算机网络中最经典的问题:TCP三次握手。我敢说,90%的程序员都能背出三次握手的流程:客户端发SYN,服务器回SYN+ACK,客户端再回ACK。但如果问“为什么是三次?两次行不行?四次行不行?”,能答上来的人不到10%。

很多人会说“为了安全”、“为了确认双方都能收发数据”,这些答案都对,但都没有说到本质上。

2.1 先看一个最通俗的类比:打电话

我给大家打个最简单的比方,TCP三次握手就像是两个人打电话:

  • 第一次握手:小明打电话给小红,说“喂,能听到我说话吗?”(客户端发SYN,请求建立连接)
  • 第二次握手:小红听到了,说“能听到,你能听到我说话吗?”(服务器回SYN+ACK,确认收到请求,并请求客户端确认)
  • 第三次握手:小明听到了,说“能听到,那我们开始说话吧”(客户端回ACK,确认收到服务器的确认,连接建立)

那为什么不能是两次呢?如果只有两次握手,会发生什么情况?

假设只有两次握手:小明说“喂,能听到我说话吗?”,小红说“能听到”,然后就开始说话了。这时候如果小明的电话信号不好,没听到小红的回答,他就会认为连接没有建立,不会说话。但小红已经认为连接建立了,会一直等着小明说话,这样就会造成资源浪费。

更严重的是,如果小明之前发过一个过期的连接请求,因为网络延迟,过了很久才到达服务器。服务器收到后,会回一个SYN+ACK,认为连接已经建立,然后一直等着小明发数据。但小明根本没有发起这个连接,不会理服务器,这样服务器就会一直占用一个连接资源,直到超时。

这就是TCP三次握手最核心的原因:防止历史连接的建立,避免服务器资源的浪费

2.2 为什么不是四次?

很多人会问,既然三次是为了确认双方的收发能力,那四次不是更保险吗?

其实四次也可以,但没有必要。因为第二次握手的时候,服务器可以把自己的SYN和ACK放在同一个包里发出去,这样就可以减少一次网络传输,提高效率。

而四次挥手之所以需要四次,是因为TCP是全双工的,双方都需要单独关闭自己的发送通道。当一方发送FIN表示自己没有数据要发送了,另一方只能回ACK确认收到,但可能还有数据要发送,所以需要等自己的数据发送完了,再发送FIN。

2.3 2026年了,这个知识点还有用吗?

很多人觉得,现在都云原生时代了,有K8s、有服务网格,谁还关心TCP三次握手啊?但恰恰是在云原生时代,这个知识点变得更加重要了。

我见过太多线上事故,都是因为开发人员不懂TCP原理导致的:

  • 服务出现大量TIME_WAIT状态,导致端口耗尽,新连接无法建立
  • 服务器出现大量CLOSE_WAIT状态,导致文件描述符耗尽
  • 长连接断开后没有重连,导致服务不可用
  • 网络超时时间设置不合理,导致请求堆积

这些问题,AI不会帮你解决,K8s也不会帮你解决,只有你自己懂TCP原理,才能快速定位和解决。

三、过拟合与欠拟合:AI训练准确率99%,上线直接崩?

接下来我们说说AI领域最基础、也是最容易踩坑的问题:过拟合与欠拟合。

我见过太多刚入门AI的朋友,对着教程敲了一下午代码,好不容易搭好一个神经网络,训练的时候看着准确率一路飙到99%,损失值跌到接近0,心里美滋滋,觉得自己马上就要跻身AI大神行列了。结果一上线,用真实用户的数据一测,准确率直接腰斩到50%,甚至还不如瞎蒙的准,当场傻眼。

还有的朋友更挫败,模型训了好几天,训练集准确率就没超过60%,怎么调参数都上不去,要么怀疑自己代码写错了,要么觉得模型太垃圾,甚至直接想放弃AI这条路。

其实这两种情况,分别就是欠拟合和过拟合。

3.1 最通俗的类比:考试背答案 vs 理解知识点

我给大家打个最通俗的比方,过拟合和欠拟合就像是学生考试:

  • 欠拟合:就像是一个学生,上课根本没听讲,课本也没看,考试的时候只能瞎蒙,平时作业做不对,考试也考不好。
  • 正常拟合:就像是一个好学生,上课认真听讲,理解了知识点,平时作业做得好,考试也能考出好成绩。
  • 过拟合:就像是一个学生,把历年的考试真题和答案都背下来了,平时做真题能考满分,但考试的时候只要题目稍微变一下,就不会做了。

这个类比非常准确,因为机器学习的本质就是“从数据中学习规律,然后对未知数据进行预测”。如果模型连训练数据都学不好,那就是欠拟合;如果模型把训练数据的所有细节都记住了,包括噪声和异常值,那就是过拟合。

3.2 本质:模型复杂度与数据量的匹配

过拟合和欠拟合的本质,其实就是模型复杂度与数据量的不匹配

  • 当模型太简单,数据量太大的时候,模型无法学习到数据中的规律,就会出现欠拟合。
  • 当模型太复杂,数据量太小的时候,模型会学习到数据中的噪声和异常值,而不是真正的规律,就会出现过拟合。

我给大家举个例子:假设你有10个样本,你用一个100层的神经网络去训练,模型肯定能把这10个样本全部记住,训练准确率100%,但给它一个新的样本,它肯定预测不准,这就是典型的过拟合。

反过来,如果你有100万个样本,你用一个只有一层的线性模型去训练,模型肯定无法学习到数据中的复杂规律,训练准确率和测试准确率都很低,这就是典型的欠拟合。

3.3 2026年了,如何解决过拟合与欠拟合?

很多人觉得,现在都大模型时代了,过拟合和欠拟合已经不是问题了,只要用大模型微调就行。但恰恰是在大模型微调的时候,过拟合问题变得更加严重了。

因为大模型本身已经非常复杂了,而我们用来微调的数据量通常都很小,很容易出现过拟合。我见过很多人微调大模型,训练集准确率99%,测试集准确率60%,就是因为过拟合了。

下面我给大家总结一下2026年解决过拟合和欠拟合的最佳实践:

解决欠拟合的方法:
  1. 增加模型复杂度:比如增加神经网络的层数、增加神经元的数量、使用更复杂的模型结构。
  2. 减少正则化强度:比如降低L2正则化的系数、关闭Dropout。
  3. 增加训练轮数:有时候模型还没训练充分,就提前停止了,也会出现欠拟合。
  4. 特征工程:提取更多有价值的特征,让模型更容易学习到规律。
解决过拟合的方法:
  1. 增加数据量:这是最根本的解决方法,数据越多,过拟合的可能性越小。
  2. 数据增强:对现有数据进行变换,生成更多的训练数据,比如图像的旋转、翻转、裁剪,文本的同义词替换、随机插入。
  3. 降低模型复杂度:比如减少神经网络的层数、减少神经元的数量、使用更简单的模型结构。
  4. 增加正则化:比如L1正则化、L2正则化、Dropout、Batch Normalization。
  5. 早停:在模型开始过拟合之前,就停止训练。
  6. 集成学习:训练多个模型,然后将它们的预测结果结合起来,比如Bagging、Boosting。

四、编译 vs 构建:代码写得溜,一编译就报错?

接下来我们说说很多程序员的噩梦:编译与构建。

我敢打赌,至少有70%的程序员,写代码的时候逻辑丝滑流畅,单元测试一遍过,结果一到编译构建环节,直接报错满天飞,不是缺依赖就是链接失败,对着Makefile/CMakeLists.txt/build.gradle文件抓瞎,最后只能去网上复制粘贴一段脚本,瞎猫碰上死耗子跑通了,却根本不知道里面每一行是干嘛的。

很多人觉得“编译构建就是工具的事,不用懂”,但恰恰是这些看似不重要的环节,最容易拖慢开发效率,甚至导致项目无法交付。

4.1 先搞清楚:编译和构建到底有什么区别?

很多人把编译和构建混为一谈,其实它们是两个完全不同的概念。我给大家打个通俗的比方:

  • 编译:就像是炒菜,把原材料(源代码)加工成成品(机器码)。
  • 构建:就像是做一顿饭,包括买菜(下载依赖)、洗菜(预处理)、炒菜(编译)、装盘(打包)、上菜(部署)一条龙服务。

具体来说:

  • 编译:是将源代码(比如C/C++/Java代码)转换成机器可以执行的二进制代码的过程。它只关心单个文件或单个模块的转换。
  • 构建:是将整个项目的所有源代码、依赖库、资源文件等整合在一起,生成最终可执行文件或安装包的过程。它包括编译、链接、打包、测试、部署等多个环节。

举个例子:你写了一个C++程序,有10个源文件。编译就是把这10个源文件分别转换成10个目标文件(.o文件)。构建就是把这10个目标文件和依赖的库文件链接在一起,生成最终的可执行文件。

4.2 为什么构建工具这么复杂?

很多人吐槽Make、CMake、Gradle这些构建工具太复杂,太难用,其实这是有原因的。

一个大型项目,可能有上万个源文件,依赖几十个第三方库,需要支持Windows、Linux、MacOS等多个平台,需要支持Debug、Release等多种构建类型,需要支持单元测试、集成测试、性能测试等多种测试环节。如果没有一个强大的构建工具,这些工作根本无法自动化完成。

我见过很多团队,因为构建工具用得不好,每次构建都需要手动执行十几个命令,耗时几个小时,严重影响开发效率。还有的团队,因为构建脚本写得不好,导致不同环境下构建出来的结果不一样,出现“在我电脑上能跑,在服务器上跑不了”的问题。

4.3 2026年了,有哪些好用的构建工具?

随着技术的发展,构建工具也在不断进化。2026年了,除了传统的Make、CMake、Gradle之外,还有很多更好用的构建工具:

  1. Bazel:Google开发的构建工具,支持多种编程语言,支持分布式构建,速度非常快,适合大型项目。
  2. xmake:国人开发的构建工具,语法简单,易于使用,支持多种编程语言,支持跨平台构建,速度比CMake快很多。
  3. Meson:专注于速度和易用性的构建工具,语法简单,支持多种编程语言,支持跨平台构建。

另外,现在很多AI工具也可以辅助生成构建脚本,比如GPT-5.4可以根据你的项目结构,自动生成CMakeLists.txt或build.gradle文件,大大降低了构建工具的使用门槛。但我还是建议大家至少要懂一点构建工具的基本原理,这样当AI生成的脚本出现问题时,你才能快速定位和解决。

五、异常处理:不是try-except包一切,而是精准捕获

最后我们说说异常处理。这是一个看似简单,但90%的程序员都做不好的事情。

我见过太多的代码,全是这种写法:

try:# 一大段代码exceptException:pass

这种写法简直就是灾难。它会把所有的异常都掩盖掉,不管是空指针异常、数组越界异常,还是数据库连接异常,都会被忽略。当程序出现bug的时候,你根本不知道哪里出了问题,只能一行一行地调试,浪费大量的时间。

5.1 异常处理的本质:不是掩盖错误,而是处理错误

很多人觉得,异常处理就是“用try-except把代码包起来,不让程序崩溃”,这其实是对异常处理最大的误解。

异常处理的本质,不是掩盖错误,而是在错误发生的时候,能够优雅地处理错误,记录错误信息,然后让程序继续运行,或者安全地退出

我给大家打个通俗的比方:异常就像是人生病了。好的异常处理就像是去医院看病,医生会根据你的症状,诊断出你得了什么病,然后给你开对应的药。而不好的异常处理就像是不管得了什么病,都吃一片止痛药,虽然暂时不疼了,但病情会越来越严重,最后可能会危及生命。

5.2 2026年了,异常处理的最佳实践

下面我给大家总结一下2026年异常处理的最佳实践:

  1. 精准捕获异常,不要捕获Exception:只捕获你知道如何处理的异常,不要捕获所有异常。比如你要打开一个文件,就只捕获FileNotFoundError,不要捕获Exception。
  2. 不要忽略异常:除非你非常确定这个异常可以忽略,否则不要用pass。至少要记录一下异常信息。
  3. 记录详细的异常信息:记录异常的时候,要记录异常的类型、异常信息、堆栈跟踪,这样才能快速定位问题。
  4. 使用异常链:在Python 3中,你可以使用raise new_exception from original_exception来保留原始异常的信息,这样可以更方便地排查问题。
  5. 在合适的层级处理异常:不要在底层代码中处理所有异常,应该把异常抛给上层,让上层在合适的地方处理。
  6. 使用自定义异常:对于业务相关的异常,应该定义自定义异常,这样可以更清晰地表达错误类型。

写在最后

今天给大家盘点了5个90%的程序员都没搞懂的编程基础概念,不知道你中了几个。

很多人觉得“基础没用,能干活就行”,觉得“AI都能写代码了,学基础干嘛”。但我要告诉大家,恰恰是在AI时代,基础变得更加重要了。

AI确实能帮我们写很多重复的代码,能帮我们提高开发效率,但它不能帮我们思考,不能帮我们解决复杂的问题。当程序出现bug的时候,当系统出现性能问题的时候,当模型出现过拟合的时候,只有你自己懂基础,才能快速定位和解决问题。

我在AI行业摸爬滚打了22年,见过太多的程序员,因为基础不牢,30岁就遇到了职业天花板,只能被行业淘汰。也见过很多的程序员,虽然不是科班出身,但基础打得非常扎实,最后成为了行业的顶尖人才。

所以,兄弟们,不要看不起基础,不要觉得基础没用。把基础打牢,你才能在技术的道路上走得更远。

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询