杂记 05
1 "env" 通常指的是虚拟环境(Virtual Environment)
我有时候会看到py的env还是什么,我不知道他们在说什么。
在 Python 开发中,你提到的 "env" 通常指的是虚拟环境(Virtual Environment),这是一个非常重要的概念,主要用于隔离不同项目的依赖包。
简单来说,虚拟环境就像是为每个 Python 项目创建一个独立的 "小天地",让不同项目可以使用各自需要的库版本,而不会互相干扰。
为什么需要虚拟环境?
假设你有两个项目:
- 项目 A 需要使用 Python 3.8 和 Django 2.2 版本
- 项目 B 需要使用 Python 3.10 和 Django 4.2 版本
如果没有虚拟环境,这两个项目的依赖包会安装在同一个地方,可能会导致版本冲突,让其中一个项目无法正常运行。
常见的虚拟环境工具
venv:Python 3.3 + 自带的虚拟环境工具,无需额外安装
bash
# 创建虚拟环境 python -m venv myenv# 激活虚拟环境 # Windows: myenv\Scripts\activate # Mac/Linux: source myenv/bin/activate# 激活后命令行会显示环境名称 (myenv) user@computer:~$# 退出虚拟环境 deactivate
conda:Anaconda 发行版自带的环境管理工具,常用于数据科学领域
pipenv 和 poetry:更现代的工具,整合了虚拟环境管理和依赖管理功能
当你看到别人说 "创建一个 env"、"激活 env" 或 "配置 env" 时,通常都是在说这些虚拟环境相关的操作。使用虚拟环境是 Python 开发的最佳实践之一,建议你在实际项目中养成使用它的习惯。
2 Conda 或者 Miniconda
Conda 或者 Miniconda,它们和 Anaconda 相关但更轻量,现在确实被很多开发者青睐。
简单说一下它们的关系和区别:
Anaconda:是一个大型集成包,包含了 Python 解释器、Conda 环境管理工具,以及数百个常用科学计算库(如 NumPy、Pandas 等)。优点是开箱即用,缺点是体积大(几个 GB)。
Miniconda:只包含 Python 解释器和 Conda 工具本身,体积很小(几十 MB)。需要什么库再自己用
conda install
安装,更灵活,现在很多开发者更倾向于用它。Conda:本身是一个跨平台的环境管理和包管理工具,既可以管理 Python 环境,也能管理其他语言的依赖。Anaconda 和 Miniconda 都包含 Conda,只是附带的库多少不同。
现在很多人推荐用 Miniconda 替代 Anaconda,因为:
- 安装包小,下载和安装更快
- 只装需要的库,避免资源浪费
- 依然能享受 Conda 的环境隔离能力
使用起来和 Anaconda 类似,比如创建环境:
bash
# 创建名为myenv的环境,指定Python版本
conda create -n myenv python=3.9# 激活环境
conda activate myenv# 安装库
conda install numpy pandas
3 NaN是什么?
在算法、编程或数据处理中,NaN 是 Not a Number(非数字)的缩写,它是一种特殊的数值类型,用来表示 “无法表示或定义的数字结果”。
1. 核心作用
NaN 的本质是 “标记错误”—— 当数学运算或数据转换无法得到有效数字时,系统不会直接崩溃,而是返回 NaN 来提示 “此处结果无效”。
2. 常见产生场景
- 数学运算无意义:比如
0 ÷ 0
(0 除以 0)、∞ - ∞
(无穷大减无穷大)。 - 非数字转数字失败:比如把字符串
"abc"
强行转成数字(Number("abc")
)、用Math.sqrt(-1)
(求负数的平方根)。 - 数据缺失 / 异常:比如读取表格时某单元格是空值,或传感器采集到无效数据,可能会被识别为 NaN。
3. 关键特性(容易踩坑)
- NaN 不等于任何值,包括它自己:比如
NaN === NaN
的结果是false
,判断一个值是否为 NaN 必须用专门的函数(如 JavaScript 中的isNaN()
、Python 中的math.isnan()
)。 - 传播性:如果运算中包含 NaN,结果通常也是 NaN(比如
10 + NaN
、NaN * 5
都会返回 NaN)。
简单说,遇到 NaN 就意味着 “这里的数字计算 / 处理出了问题,需要检查输入或逻辑”。
4 原码、反码和补码有何意义
原码、反码和补码是计算机中表示有符号整数的三种编码方式,它们的设计本质是为了解决带符号数的运算问题,尤其是减法如何转化为加法计算(因为计算机硬件实现加法比减法更简单高效)。
1. 原码(Sign-Magnitude)
- 表示方法:最高位为符号位(0 表示正,1 表示负),其余位表示数值的绝对值。
- 例如:8 位二进制中,
+5
的原码是00000101
,-5
的原码是10000101
。
- 例如:8 位二进制中,
- 意义:直观易懂,直接对应人类对正负数字的理解。
- 问题:
- 0 有两种表示:
+0
(00000000)和-0
(10000000),浪费存储空间。 - 减法无法直接转化为加法(如
5 - 3
不能直接用5 + (-3)
的原码计算,结果会出错)。
- 0 有两种表示:
2. 反码(One's Complement)
- 表示方法:
- 正数的反码与原码相同(如
+5
反码为00000101
)。 - 负数的反码是对原码除符号位外的所有位取反(如
-5
反码为11111010
)。
- 正数的反码与原码相同(如
- 意义:尝试解决减法问题,通过反码可以将减法转化为加法(
a - b = a + (-b)
的反码)。 - 问题:
- 0 仍然有两种表示(
+0
反码00000000
,-0
反码11111111
)。 - 加法运算可能产生进位,需要额外处理(如
11111111 + 00000001
结果为100000000
,需丢弃最高位并加 1,增加硬件复杂度)。
- 0 仍然有两种表示(
3. 补码(Two's Complement)
- 表示方法:
- 正数的补码与原码相同(如
+5
补码为00000101
)。 - 负数的补码是其反码加 1(如
-5
反码11111010
→ 补码11111011
)。
- 正数的补码与原码相同(如
- 核心意义:彻底解决了前两种编码的缺陷,是现代计算机普遍采用的编码方式:
- 0 只有一种表示:
00000000
(补码中没有-0
),节省存储空间。 - 减法完全转化为加法:
a - b
等价于a + (-b)
的补码,无需额外处理减法逻辑。 - 运算规则统一:加法时符号位与数值位一起参与运算,进位自然丢弃,硬件实现简单。
- 0 只有一种表示:
总结
- 原码:直观但无法高效运算,仅用于早期简单场景。
- 反码:过渡方案,解决了部分运算问题但仍有缺陷。
- 补码:最终解决方案,通过统一加减法为加法运算,简化了计算机硬件设计,同时避免了 0 的二义性,成为现代计算机表示有符号整数的标准方式。
【学会原码补码反码的转换有什么意义?】
学会原码、反码、补码的转换,本质是理解计算机处理有符号整数的底层逻辑,这对编程和系统开发有实际意义,主要体现在以下几个方面:
1. 理解计算机如何 “算减法”
计算机硬件本质上只有加法器(实现加法比减法法简单),减法需要通过 “加负数” 来间接实现。而补码的核心作用就是让 “减法变加法” 成为可能。
例如计算 5 - 3
,计算机实际会算 5 + (-3)
:
- 用补码表示时,
-3
的补码是对3
的补码取反加 1,这样5 + (-3)
的补码运算结果,恰好等于2
的补码。
掌握转换规则后,你能明白 “看似减法的运算,底层是如何通过补码转化为加法的”,理解为什么计算机能高效处理带符号数的运算。
2. 排查底层数据问题
在调试涉及二进制、位运算的代码时(如嵌入式开发、系统级编程),经常需要直接处理数值的二进制表示。
例如:
- 为什么
int a = 128; char b = a;
会得到-128
(而非 128)?
因为 8 位 char 的补码范围是-128~127
,128 超出范围后,其二进制10000000
在补码中表示-128
。 - 为什么
(unsigned char)0xff
是 255,而(char)0xff
是-1
?
因为有符号数用补码解析:0xff
作为 8 位补码,符号位为 1(负),数值部分取反加 1 后是0x01
,所以表示-1
。
不懂补码转换,就无法解释这类 “看似矛盾” 的数值问题。
3. 理解编程语言的数值特性
许多编程语言的整数行为与补码直接相关:
- Python 的整数没有范围限制,但 C/C++、Java 等语言的固定长度整数(如 int32)溢出时,本质是补码的 “截断” 或 “循环”(例如
int32_t(2147483647 + 1) = -2147483648
,正是 32 位补码的溢出结果)。 - 位运算(如移位、与或非)的结果,必须结合补码规则才能正确解读(例如对负数右移时,符号位是否参与填充,取决于语言对补码的处理方式)。
4. 底层开发的基础
如果从事嵌入式、操作系统、驱动开发等底层工作,直接操作二进制数据是常态:
- 硬件寄存器的数值往往需要用补码解析(如传感器返回的带符号温度值)。
- 数据传输时(如网络协议、设备通信),二进制流的解析必须遵循补码规则(否则会出现数值错误)。
总结
原码、反码、补码的转换规则,是计算机 “用二进制表示和计算有符号数” 的底层逻辑。学会它们,不仅能帮你理解 “计算机为什么能算对”,更能在调试底层问题、处理数值异常、进行系统级开发时,快速定位问题本质 —— 这是从 “会用” 到 “理解原理” 的重要一步。
5 轮子项目是什么
在编程和软件开发领域,“轮子项目”(通常说 “造轮子”)指的是重复开发已经存在的功能或工具。这里的 “轮子” 比喻那些已经被广泛使用、成熟稳定的基础组件、库、框架或工具(比如排序算法、日期处理函数、网络请求库等)。
为什么会有 “造轮子”?
学习目的:新手通过重复实现基础功能(如手写一个简单的链表、HTTP 服务器),能深入理解底层原理,是重要的学习手段。
定制需求:现有工具可能无法满足特定场景(如性能优化、适配特殊硬件),此时需要 “造一个更合适的轮子”。例如,某些高频交易系统会自研更高效的网络库,而非使用通用库。
避免依赖:商业项目中,为了减少对第三方库的依赖(避免版本兼容问题、许可证限制等),可能会自研核心功能。
争议点
不推荐的情况:在生产环境中,盲目重复开发成熟工具(如自己写一个 JSON 解析器替代
JSON.parse
)通常被认为是低效的,因为现有 “轮子” 经过了大量测试和优化,稳定性更有保障。合理的情况:当现有工具确实无法满足需求,或为了学习、研究目的时,“造轮子” 是有意义的。
简单说,“轮子项目” 本质是对已有功能的重复实现,其价值取决于目的 —— 是为了学习、定制,还是无意义的重复劳动。
【怎么样避免是无意义的劳动呢?在简历里面写轮子项目有用吗?】
要避免 “无意义的造轮子”,核心是明确目的和价值;而简历中写 “轮子项目” 是否有用,关键看项目能否体现你的能力深度。
一、如何避免无意义的 “造轮子”?
先调研,再动手
开发前先确认:现有工具是否真的无法满足需求?比如想做一个 “日志工具”,先调研市面上的log4j
、winston
等库是否缺你需要的核心功能(如特殊格式输出、低延迟)。如果只是 “想自己写一个”,而非解决实际问题,很可能变成无意义劳动。绑定具体场景,解决真实问题
有意义的 “轮子” 一定对应具体痛点。例如:- 不是单纯 “实现一个排序算法”,而是 “为百万级电商 SKU 设计一个内存占用更低的排序工具”;
- 不是 “写一个 HTTP 客户端”,而是 “针对公司内部 API 协议,优化请求重试和加密逻辑的轻量客户端”。
带着场景的轮子,才有存在的价值。
以 “超越现有” 为目标
要么比现有工具更轻量、更快、更易用,要么解决了特定场景的痛点(如适配老旧硬件、满足严格合规要求)。如果只是 “重复实现”,且质量不如成熟工具,就容易沦为无意义劳动。
二、简历中写 “轮子项目” 有用吗?
有用,但分情况:
加分的情况:
- 项目体现 “深度思考”:比如你实现了一个简化版 ORM 框架,能说明 “我理解数据库连接池、SQL 映射的底层原理”;
- 解决了实际问题:比如 “因团队依赖的第三方库有性能瓶颈,自研了轻量替代方案,使接口响应速度提升 30%”;
- 技术栈有亮点:比如用 C 实现了线程安全的内存池,能体现对操作系统、数据结构的掌握。
减分的情况:
- 单纯重复基础功能:比如 “实现了一个 Python 版的冒泡排序”“写了一个简单的 JSON 解析器”(这些属于练习题,无法体现竞争力);(哈哈哈哈哈写了一个冒泡排序是什么鬼哈哈哈哈哈)
- 没有技术深度:只说 “造了一个轮子”,但说不清解决了什么问题、比现有工具好在哪里;
- 质量粗糙:代码无注释、无测试、性能比成熟工具差(反而暴露能力不足)。
总结
- 避免无意义劳动的核心:让 “造轮子” 服务于 “解决问题” 或 “深度学习”,而非单纯重复。
- 简历中写轮子项目的关键:突出 “你通过这个项目掌握了什么底层原理”“解决了什么实际问题”,而非只说 “我造了个轮子”。
例如,与其写 “实现了一个 Web 框架”,不如写 “为理解中间件原理,实现了简化版 Web 框架,包含路由分发和请求拦截功能,并用它搭建了公司内部管理系统的后端”—— 后者更能体现你的技术思考和实践能力。