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

学习日志40 python

1 numpy模块

NumPy(Numerical Python)是 Python 中用于科学计算的基础库,提供了高性能的多维数组对象,以及大量用于数组操作的函数。以下是对它的详细介绍:

1. 核心数据结构 - ndarray

  • 定义:ndarray(N-dimensional array object,多维数组对象)是 NumPy 的核心数据结构,它表示一个由相同类型元素组成的多维数组。
  • 特点
    • 高效存储:ndarray 在内存中以连续的方式存储数据,这使得对数据的访问和操作非常高效。与 Python 内置的列表相比,ndarray 占用的内存更少,并且在执行数值计算时速度更快。
    • 固定数据类型:数组中的所有元素必须具有相同的数据类型,这在创建数组时就需要指定。常见的数据类型包括 int32float64bool 等。例如,np.array([1, 2, 3], dtype=np.int32)
    • 多维索引:可以通过整数元组进行多维索引和切片操作,方便地访问和修改数组中的元素。如 arr[0, 1] 表示访问二维数组 arr 中第 0 行第 1 列的元素。

2. 创建 ndarray 数组

  • 使用 np.array () 函数:可以将 Python 列表或元组转换为 ndarray 数组。例如:

python

运行

import numpy as np
list_data = [1, 2, 3, 4]
arr = np.array(list_data)
  • 特殊数组创建函数
    • np.zeros(shape):创建指定形状的全 0 数组,如 np.zeros((3, 4)) 创建一个 3 行 4 列的全 0 二维数组。
    • np.ones(shape):创建指定形状的全 1 数组,如 np.ones((2, 2)) 创建一个 2 行 2 列的全 1 二维数组。
    • np.arange(start, stop, step):类似于 Python 的 range() 函数,创建一个等差数组,如 np.arange(0, 10, 2) 生成 [0, 2, 4, 6, 8]

3. 数组操作

  • 算术运算:可以对 ndarray 数组进行各种算术运算,如加、减、乘、除等。这些运算都是按元素进行的。例如:

python

运行

arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
result = arr1 + arr2  # 结果为 [5, 7, 9]
  • 广播机制:当对形状不同的数组进行运算时,NumPy 会自动尝试使用广播机制来使运算可行。例如,一个一维数组和一个二维数组可以在满足一定条件下进行运算。
  • 索引和切片:支持灵活的索引和切片操作,与 Python 列表类似,但更强大。例如:

python

运行

arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr[0, 1])  # 输出 2
print(arr[:, 1])  # 输出 [2, 5],获取第二列

4. 数学函数

NumPy 提供了大量的数学函数,可以直接应用于数组,如三角函数(np.sin()np.cos() 等)、指数和对数函数(np.exp()np.log() 等)、统计函数(np.mean()np.std() 等)。例如:

python

运行

arr = np.array([1, 2, 3])
print(np.mean(arr))  # 输出 2.0,计算数组元素的平均值

5. 线性代数运算

在科学计算和机器学习中,线性代数运算非常常见。NumPy 提供了丰富的线性代数函数,如矩阵乘法(np.dot())、求逆矩阵(np.linalg.inv())、求行列式(np.linalg.det())等。例如:

python

运行

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
c = np.dot(a, b)  # 计算矩阵 a 和 b 的乘积

6. 应用场景

  • 科学计算:在物理模拟、数据分析、数值计算等领域,用于处理大规模的数值数据。
  • 机器学习和深度学习:是 Scikit-learn、TensorFlow、PyTorch 等机器学习和深度学习库的基础,用于数据预处理、模型训练中的张量运算等。
  • 图像处理:可以用来表示和处理图像数据,进行图像滤波、变换等操作。

NumPy 凭借其高效的数组操作和丰富的函数库,极大地简化了 Python 中科学计算的过程,是 Python 科学计算生态系统中不可或缺的一部分。

2 Python中的链式比较3>2>2等价于(3>2) and (2>2)

虽然3>2为True,但2>2为False,因此整体结果为False。

Python 的链式比较是一种简洁的语法,允许在一个表达式中连续使用多个比较运算符(如><>=<===!=等),用来同时判断多个条件是否成立。其核心逻辑是将多个比较通过and连接,只有所有条件都满足时,整体结果才为True

1. 基本语法与等价逻辑

链式比较的格式为:
a 比较符1 b 比较符2 c 比较符3 ...

它等价于:
(a 比较符1 b) and (b 比较符2 c) and (c 比较符3 ...)

例如:

  • 3 > 2 > 1 等价于 (3>2) and (2>1),结果为True(两个条件都满足)。
  • 3 > 2 > 2 等价于 (3>2) and (2>2),结果为False(第二个条件不满足)。
  • 5 == 5 < 6 等价于 (5==5) and (5<6),结果为True

2. 为什么要使用链式比较?

相比拆分成多个and连接的表达式,链式比较的优势是:

  • 更简洁:减少重复变量的书写。例如x > 0 and x < 10可以简写为0 < x < 10
  • 可读性更高:更符合人类的自然语言逻辑(如 “x 大于 0 且小于 10”)。

3. 注意事项

  • 变量只计算一次:在链式比较中,中间的变量(如a < b < c中的b)只会被计算一次,而拆分后的(a<b) and (b<c)也会计算一次b,两者效果一致,不会有性能差异。
    例:x = 5; 1 < x < 10 中,x只被读取一次。

  • 支持多种比较运算符混合:只要逻辑合理,可混合使用不同运算符。
    例:1 <= x < 10(x 大于等于 1 且小于 10)、a != b == c(a 不等于 b,且 b 等于 c)。

  • 短路逻辑:和and一样,链式比较也遵循 “短路原则”—— 如果前面的条件不满足,后面的条件会直接跳过,不再计算。
    例:3 > 5 > 2 中,3>5False,直接返回False,不会再判断5>2

4. 常见错误

  • 不要混淆数学中的 “连续区间” 表达:
    例如 “x 在 1 到 10 之间” 在数学中写为1 < x < 10,这在 Python 中是合法的,但其他语言(如 C、Java)中必须写成x>1 && x<10,否则会报错。

  • 避免逻辑矛盾的表达式:
    例如3 > 2 < 1 等价于 (3>2) and (2<1),结果为False,虽然语法合法,但逻辑上可能不符合预期。

通过链式比较,Python 让条件判断的代码更简洁、直观,尤其适合范围判断场景(如数值区间、年龄范围等)。理解其等价于and连接的多个条件,就能轻松掌握其用法。

核心就是:代码的链式逻辑准确对应数学上的“同时成立”

只有当 Python 链式比较的逻辑,和数学中 “多个条件必须同时成立” 的逻辑完全对应时,代码输出的结果才会与数学判断一致(为 True)

可以通过两个具体场景进一步明确这种 “对应关系”:

1. 对应数学 “区间范围”(最典型的 “同时成立”)

数学中描述 “一个数在某两个值之间”,本质就是 “大于左边界  小于右边界”(两个条件同时成立),这和链式比较的逻辑完全匹配。

  • 数学:5 < x < 10(x 大于 5, x 小于 10)
  • 代码:5 < x < 10(等价于 (5 < x) and (x < 10)
    只要 x 的取值满足数学上的区间,代码结果就为 True(比如 x=7 时,5<77<10都成立,整体为 True)。

2. 对应数学 “多个独立条件”(非区间,但需同时满足)

除了区间,数学中也会有 “多个独立条件必须同时满足” 的场景,链式比较同样能对应。

  • 数学:a > b  b > c(a 大于 b,同时 b 大于 c,即 a > b > c)
  • 代码:a > b > c(等价于 (a > b) and (b > c)
    比如 a=4、b=3、c=2 时,数学上 4>3>2 成立,代码结果也为 True;若 b=5(a=4 < b=5),则数学上不成立,代码结果为 False。

关键反例:若不对应 “同时成立”,则结果不符

如果数学上需要的是 “任意一个条件成立”(而非 “同时成立”),此时用链式比较就会出错 —— 因为链式比较只认 “and”,不认 “or”。

  • 数学:x < 2  x > 5(x 不在 2~5 之间即可,无需两个条件同时满足)
  • 错误代码:x < 2 > 5(等价于 (x<2) and (2>5)
    数学上 x=1 时满足 “x<2”,但代码中2>5永远是 False,整体结果为 False—— 这就是因为代码逻辑(and)和数学逻辑(or)不对应,导致结果不符。

综上:链式比较是 Python 对数学 “多条件同时成立” 逻辑的一种简洁语法实现。只有当你想表达的数学关系是 “所有条件必须一起满足” 时,用链式比较才能得到和数学判断一致的 True;反之则会出错。

capitalize() 方法

在 Python 3 中,capitalize() 方法用于将字符串的第一个字符转换为大写,而将其余字符转换为小写,并且不会修改原字符串,而是返回一个新的字符串。

例如:

python

运行

text = "hello world"
new_text = text.capitalize()print(text)      # 输出: hello world (原字符串不变)
print(new_text)  # 输出: Hello world (新字符串)

这个方法非常适合处理需要规范化句子首字母大写的场景,同时又能保持原始字符串的完整性。

联想到upper和lower是对全字符操作的,敲了以下代码附上输出。

a = "python"
b = a.capitalize()
print(a)
print(b)
b = a.upper()
print(b)
b = b.lower()
print(b)

输出

python
Python
PYTHON
python

除了capitalize是首字符,我发现这个print是按序施行的,类似于流式管理吗(?不清楚),这里的内存是怎么放的?

测试一下

a = "python"
b = a.capitalize()
print(a)
print(b)
print(id(b))
b = a.upper()
print(b)
print(id(b))
b = b.lower()
print(b)
print(id(b))

输出

python
Python
2202715617680
PYTHON
2202715617728
python
2202715617680

最后的内存地址不变?,值改变,应该是因为只对值操作没有创建新的对象(开辟新的内存空间),应该是这样,一知半解,问问ai我说的对不对。

====================================

你的观察很细致!不过关于内存地址的理解需要稍微修正一下:每次字符串方法调用(capitalize ()、upper ()、lower ())都会创建新的字符串对象而不是在原有对象上修改。

从你的测试结果来看:

plaintext

python
Python
2202715617680  # b指向capitalize()创建的新对象
PYTHON
2202715617728  # b指向upper()创建的新对象
python
2202715617680  # b指向lower()创建的新对象(恰好与第一个对象地址相同)

这里最后一个id(b)与第一个相同,并不是因为 "没有创建新对象",而是因为:

  1. Python 会对短字符串(尤其是纯小写 / 大写的简单字符串)进行缓存(称为 "字符串驻留" 机制)
  2. b.lower()生成的 "python" 与最初a的值相同时,Python 直接复用了已存在的缓存对象
  3. 这是一种内存优化策略,并非修改原有对象

关键点:

  • 字符串在 Python 中是不可变类型,任何修改操作(包括大小写转换)都会产生新对象(划重点)
  • 变量b只是不断指向新创建的对象,原有对象如果没有被引用会被垃圾回收
  • 内存地址相同只是巧合(缓存机制导致),不能认为是 "值改变而对象不变"

可以理解为:变量像一个标签,每次调用字符串方法后,这个标签就从旧对象贴到了新对象上,而不是在旧对象上修改内容。

------------------------------------------------------------------

你对代码执行过程和内存地址变化的观察很深入,其中一些细节可以进一步明确,帮你厘清不确定的地方:

1. 关于 "print 按序施行,类似于流式管理" 的理解

Python 代码的执行是自上而下、顺序执行的,这属于程序的基本执行流程,而非特殊的 "流式管理"。

  • 每一行代码按照书写顺序依次执行
  • print()函数会在执行到该行时立即输出结果
  • 变量b的值会被后续赋值语句覆盖(如b = a.upper()会覆盖之前b = a.capitalize()的结果)

这种顺序执行是绝大多数编程语言的基础特性,确保了代码逻辑的可预测性。

2. 关于内存地址变化的核心原理(修正你的理解)

你的测试中id(b)出现重复(最后一个地址与第一个相同),并非因为 "没有创建新对象",而是由两个关键机制导致:

(1)字符串是不可变类型
  • 任何对字符串的修改操作(包括capitalize()/upper()/lower()一定会创建新对象,原字符串始终不变
  • 例如b = a.upper()中,upper()会生成全新的 "PYTHON" 字符串,再让b指向它(原b指向的 "Python" 对象若无人引用,会被垃圾回收)
(2)字符串驻留(String Interning)机制
  • Python 会对符合特定条件的字符串(如纯字母、数字、下划线组成的短字符串)进行缓存,避免重复创建相同内容的对象
  • b.lower()生成 "python" 时,由于这个字符串与最初的a = "python"内容完全相同,且符合驻留条件,Python 会让新对象直接复用已缓存的 "python" 地址
  • 这就是最后一个id(b)与第一个id(b)相同的原因 —— 不是修改旧对象,而是新生成的对象恰好复用了缓存地址
验证:如果字符串不符合驻留条件

python

运行

a = "python!"  # 包含特殊字符,不被驻留
b = a.capitalize()  # "Python!"
print(id(b))
b = b.lower()       # "python!"
print(id(b))  # 两次id会不同,因为不触发驻留

3. 总结关键结论

  • 变量b的本质:只是一个 "标签",每次赋值都会让它指向新的对象(旧对象若无人引用则被回收)
  • 对象的不可变性:字符串一旦创建就无法修改,所有 "修改" 都是生成新对象
  • 地址重复的原因:是 Python 的缓存优化(字符串驻留),而非 "值变而对象不变"

你的测试方法(用id()追踪对象)非常好,这是理解 Python 内存管理的有效手段~

4 如何在Python中实现流式处理?

在 Python 中,"流式处理" 通常指对数据进行增量式处理(边产生边处理,而非一次性加载全部数据),适用于大型文件、实时数据流或内存受限的场景。实现方式主要有以下几种:

1. 处理大型文件时的流式读取

对于大文件(如 GB 级日志文件),直接用 read() 会一次性加载到内存,可能导致内存溢出。流式处理通过逐行读取实现:

python

运行

# 流式读取大文件
with open("large_file.txt", "r") as f:for line in f:  # 逐行读取,每次只加载一行到内存process_line(line)  # 处理单行数据(如解析、过滤等)

原理:文件对象是可迭代对象,迭代时会自动按需加载数据,而非一次性读取全部内容。

2. 使用生成器(Generator)实现自定义流

生成器通过 yield 关键字增量产生数据,每次迭代返回一个值,适合构建自定义数据流:

python

运行

def data_stream():"""生成器:模拟源源不断产生数据的流"""for i in range(1000000):yield i  # 每次返回一个值,暂停并保存状态# 流式处理生成器的数据
for data in data_stream():result = process_data(data)  # 逐个处理数据if result > 1000:  # 可随时中断处理break

优势:生成器本身不存储完整数据,内存占用极低,支持 "产生一个、处理一个" 的模式。

3. 处理实时数据流(如网络数据)

对于网络请求、传感器数据等实时流,可结合异步 I/O 或线程实现持续处理:

python

运行

import socketdef network_stream(host, port):"""流式处理网络数据"""with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:s.bind((host, port))s.listen()conn, addr = s.accept()with conn:while True:data = conn.recv(1024)  # 每次接收1KB数据if not data:breakprocess_network_data(data)  # 实时处理

4. 使用专业库处理复杂流

对于需要窗口计算、状态管理的复杂流(如实时统计、ETL 等),可使用专用库:

  • itertools:标准库,提供 islice(切片流)、chain(拼接流)等工具

    python

    运行

    from itertools import islice# 从无限流中取前10个元素处理
    for item in islice(data_stream(), 10):process(item)
    
  • pandas:处理大型数据集时,可通过 chunksize 分块读取 CSV/Excel

    python

    运行

    import pandas as pd# 每次读取1000行数据处理
    for chunk in pd.read_csv("large_data.csv", chunksize=1000):process_chunk(chunk)
    

  • Apache Kafka + confluent-kafka-python:处理分布式实时数据流

  • PySpark:大数据场景下的分布式流式处理

核心思想

流式处理的关键是避免一次性加载全部数据,通过 "产生 - 处理 - 丢弃" 的模式,用有限内存处理无限或海量数据。选择哪种方式取决于数据来源(文件 / 网络 / 数据库)和处理复杂度。

5 sort()与sorted()方法

在 Python 中,sort() 和 sorted() 都用于对数据进行排序,但它们在使用方式、返回值和适用对象上有显著区别:

1. sort() 方法

  • 适用对象:仅用于列表(list),是列表的内置方法

  • 排序方式:对列表原地排序(直接修改原列表,不会创建新列表)

  • 返回值:返回 None(因此不能直接赋值给变量)

  • 语法list.sort(key=None, reverse=False)

    • key:用于指定排序依据的函数(如 key=str.lower 忽略大小写排序)
    • reverse:是否反转排序结果(False 升序,True 降序,默认 False

示例

python

运行

nums = [3, 1, 4, 2]
result = nums.sort()  # 原地排序原列表print(nums)      # 输出: [1, 2, 3, 4](原列表已被修改)
print(result)    # 输出: None(无返回值)

2. sorted() 函数

  • 适用对象:可对所有可迭代对象排序(列表、元组、字符串、字典等)

  • 排序方式不修改原对象,而是创建并返回一个新的排序后的列表

  • 返回值:返回排序后的新列表

  • 语法sorted(iterable, key=None, reverse=False)

    • 参数含义同 sort(),但第一个参数是待排序的可迭代对象

示例

python

运行

# 对列表排序
nums = [3, 1, 4, 2]
new_nums = sorted(nums)  # 创建新列表print(nums)      # 输出: [3, 1, 4, 2](原列表不变)
print(new_nums)  # 输出: [1, 2, 3, 4](新列表)# 对元组排序(返回列表)
tup = (3, 1, 4, 2)
sorted_tup = sorted(tup)
print(sorted_tup)  # 输出: [1, 2, 3, 4](元组被转为列表)# 对字符串排序(按字符ASCII值)
text = "bac"
sorted_text = sorted(text)
print(sorted_text)  # 输出: ['a', 'b', 'c']

3. 核心区别总结

特性sort()sorted()
适用对象仅列表(list所有可迭代对象
是否修改原对象是(原地排序)否(返回新列表)
返回值None排序后的新列表
内存占用较低(无需创建新对象)较高(需创建新对象)

4. 选择建议

  • 若要排序列表允许修改原列表,用 sort()(更节省内存)
  • 若要排序非列表对象(如元组、字典),或需要保留原对象,用 sorted()
  • 两者都支持 key 和 reverse 参数,可实现复杂排序(如按字典的某个键排序)

复杂排序示例

python

运行

# 按字典的"age"键排序
people = [{"name": "Bob", "age": 25}, {"name": "Alice", "age": 20}]
sorted_people = sorted(people, key=lambda x: x["age"])
print(sorted_people)  # 输出: [{"name": "Alice", "age": 20}, {"name": "Bob", "age": 25}]

自己尝试、测试

list = [1,3,4,2]
list.sort()
print(list.sort())
sorted(list)
print(sorted(list))

输出

None
[1, 2, 3, 4]

你的代码执行结果可以拆解为两个部分来理解,核心原因在于 sort() 和 sorted() 的返回值特性不同:

1. 关于 print(list.sort()) 输出 None

  • list.sort() 是列表的原地排序方法,它会直接修改原列表,但返回值为 None(这是 Python 中所有 "原地修改" 方法的设计规范)。

  • 当你执行 print(list.sort()) 时,实际上是在打印 sort() 方法的返回值,也就是 None

    代码执行过程:

    python

    运行

    list = [1,3,4,2]
    list.sort()  # 原列表被修改为 [1,2,3,4],但无返回值
    print(list.sort())  # 打印的是第二次调用 sort() 的返回值 None
    

2. 关于 print(sorted(list)) 输出 [1,2,3,4]

  • sorted(list) 是内置函数,它不会修改原列表,而是返回一个新的排序后的列表

  • 当你执行 print(sorted(list)) 时,打印的是这个新生成的排序后列表。

    代码执行过程:

    python

    运行

    sorted(list)  # 对已排序的 list 再次排序,返回新列表 [1,2,3,4](但未赋值给变量)
    print(sorted(list))  # 打印这个新列表,因此输出 [1,2,3,4]
    

关键结论

  • sort() 无返回值(返回 None),仅用于原地修改列表。
  • sorted() 有返回值,返回排序后的新列表,不影响原对象。

如果想打印排序后的列表,正确的写法是:

python

运行

list = [1,3,4,2]
list.sort()  # 原地排序
print(list)  # 直接打印修改后的原列表,输出 [1,2,3,4]

或者用 sorted()

python

运行

list = [1,3,4,2]
print(sorted(list))  # 打印排序后的新列表,输出 [1,2,3,4]
http://www.xdnf.cn/news/1382401.html

相关文章:

  • 微服务即时通信系统(十三)--- 项目部署
  • 【后端】微服务后端鉴权方案
  • 虚函数指针和虚函数表的创建时机和存放位置
  • 【Linux知识】Linux 设置账号密码永不过期
  • 完整代码注释:实现 Qt 的 TCP 客户端,实现和服务器通信
  • 【LINUX网络】TCP原理
  • WEEX唯客上线C2C交易平台:打造安全便捷的用户交易体验
  • 现在购买PCIe 5.0 SSD是否是最好的时机?
  • 前端实现Linux查询平台:打造高效运维工作流
  • [光学原理与应用-320]:光学产品不同阶段使用的工具软件、对应的输出文件
  • 华为S5720S重置密码
  • c语言动态数组扩容
  • MCU平台化实践方案
  • STL库——list(类函数学习)
  • 财务数据报销画像技术实现:从数据采集到智能决策的全流程解析
  • 【AI自动化】VSCode+Playwright+codegen+nodejs自动化脚本生成
  • 当new一块内存时,操作系统做了哪些事情
  • 软考 系统架构设计师系列知识点之杂项集萃(134)
  • leetcode算法刷题的第二十天
  • 鸿蒙OS与Rust整合开发流程
  • 面试tips--JVM(3)--类加载过程
  • 动态加载和异步调用tasklet/workqueue day63 ay64
  • 中国剩余定理(以及扩展..)
  • .Net Core Web 架构(管道机制)的底层实现
  • [光学原理与应用-321]:皮秒深紫外激光器产品不同阶段使用的工具软件、对应的输出文件
  • 【黑客技术零基础入门】2025最新黑客工具软件大全,零基础入门到精通,收藏这篇就够了!
  • JAVA全栈Redis篇————List常用命令讲解
  • 【架构师干货】软件工程
  • Linux学习-TCP并发服务器构建(epoll)
  • Cesium 入门教程(十一):Camera相机功能展示