python学到什么程度算入门,python从入门到精通好吗
本篇文章给大家谈谈python学到什么程度算入门,以及python从入门到精通好吗,希望对各位有所帮助,不要忘了收藏本站喔。
学习 Python 之 进阶学习
-
- 一切皆对象
-
- 1. 变量和函数皆对象
- 2. 模块和类皆对象
- 3. 对象的基本操作
-
- (1). 可以赋值给变量
- (2). 可以添加到集合中
- (3). 可以作为函数参数
- (4). 可以作为函数返回值返回
- 4. object, type, class之间的关系
-
- (1). object类
- (2).type类和type对象
- 闭包
-
- 1. 查看闭包
-
- (1). 查看闭包
- (2). 查看环境变量
- 2. 分析闭包
- 3. 闭包的用处
- Lambda 表达式
-
- 1. 匿名函数
- 2. 三元表达式
- 3. map类
- 4. map与lambda表达式结合使用
- 5. reduce函数
-
- ```reduce()```函数运算原理
- 6. filter函数
- 装饰器
-
- 1. 引例
- 2. 装饰器
- 3. 装饰器使用
- 4. 对带有参数的函数定义装饰器
- 5. 带有参数的装饰器的理解
- 6. 装饰器完整定义
- 7. 使用python装饰器保存内置变量的值
- 8. 数据类装饰器 dataclass
- 用字典映射代替switch case
- 列表推导式
-
- (1). 简单使用
- (2). 带有条件的列表推导式
- (3). 使用列表推导式创建元组
- (4). 字典列表推导式
-
- items()
- 字典推导字典
- 函数式编程
- 迭代器
-
- (1). 可迭代对象 和 迭代器
- (2). 自定义迭代器
- 生成器
- 海象运算符 :=
一切皆对象
1. 变量和函数皆对象
在python中, 所有的变量函数都是一个对象
print(type(1))
print(type(1.))
print(type(True))
print(type(None))
结果:
<class 'int'>
<class 'float'>
<class 'bool'>
<class 'NoneType'>
可以看出, 变量都是对象, 它们的类型都是class, 再看看函数
def f():passprint(type(f))
结果:
<class 'function'>
从上面的例子可以看出, 实际上函数就是一个对象, 那么函数可以当某个函数的参数和返回值了
2. 模块和类皆对象
就连模块和类都是对象
import sysprint(type(sys))
class A:passprint(type(A))
结果:
<class 'module'>
<class 'type'>
3. 对象的基本操作
(1). 可以赋值给变量
(2). 可以添加到集合中
(3). 可以作为函数参数
(4). 可以作为函数返回值返回
4. object, type, class之间的关系
(1). object类
object类
是所有类都要继承的一个基础类(父类)
class People:pass
print(People.__bases__)
结果:
(<class 'object'>,)
(2).type类和type对象
type()
函数查看变量类型, 但是type也是一个类, 还是一个对象
a = 1
print(type(a))
print(type(int))
结果:
<class 'int'>
<class 'type'>
因此, type类 生成 int类, int类 生成 1, 1 赋值给 a, 所以 a是int类的对象
所以, type类生成其他类
print(type.__bases__)
print(type(type))
print(type(object))
print(object.__bases__)
结果:
(<class 'object'>,)
<class 'type'>
<class 'type'>
()
可以看出, object类的父类是空
type类继承object类, type类又生成object类
type类生成type类
闭包
一个函数中的变量由其外部环境变量所决定的整体, 即函数 + 环境变量
闭包的意义: 保存了函数, 和函数定义时的变量
def func1():a = 5def ax2(x):return a * x * 2return ax2
a 是环境变量, ax2()是函数, 它们构成了一个闭包
1. 查看闭包
(1). 查看闭包
只有闭包才拥有内置属性__closure__
def func1():a = 5def ax2(x):return a * x * 2return ax2f = func1()
print(f.__closure__)
(<cell at 0x0000025E9917AF50: int object at 0x0000025E99010170>,)
(2). 查看环境变量
def func1():a = 5def ax2(x):return a * x * 2return ax2f = func1()
print(f.__closure__[0].cell_contents)
5
2. 分析闭包
函数里定义变量后不是闭包
def fun1():a = 5def fun2():b = 10return breturn fun2f = fun1()
print(f.__closure__)
None
def fun1():a = 5def fun2():return areturn fun2f = fun1()
print(f.__closure__)
(<cell at 0x0000025E9917AF50: int object at 0x0000025E99010170>,)
3. 闭包的用处
问题: 实现函数, 每次返回结果, 要在加入上一次的结果
假设开始 x = 0, 函数名是 add()
第一次 add(5), x = 5
第二次 add(10), x = 15
第三次 add(40), x = 40
x的值是在上一次的结果上叠加
- 不用闭包
x = 0def add(v):global xx += vreturn xprint('第一次:' , add(1))
print('第二次:' , add(5))
print('第三次:' , add(6))
print('第四次:' , add(10))
结果
第一次: 1
第二次: 6
第三次: 12
第四次: 22
- 使用闭包
x = 0def start(x):def add(v):nonlocal xx += vreturn xreturn addadd = start(x)
print('第一次:' , add(1))
print('第二次:' , add(5))
print('第三次:' , add(6))
print('第四次:' , add(10))
使用nonlocal
关键字
闭包的意义在于可以记录了上一次的值
Lambda 表达式
1. 匿名函数
没有函数名的函数
语法:
lambda parameter_list: expression
定义使用labmda
关键字
expression只能是表达式
def add(x, y):return x + yf = lambda x, y: x + y
print(f(1, 2))
2. 三元表达式
条件为真返回结果 if 条件 else 条件为假返回结果
x = 1
y = 6
print(x if x > y else y)
如果 x > y 返回 x 的值, 否则返回 y 的值
3. map类
map类接收两个参数, 一个是函数, 另一个是序列
map的使用方法是, 对序列中的每一个元素都进行前面函数的操作, 并把结果存放新的序列中, 最后返回
x = [1, 2, 3]def square(x):return x * xr = map(square, x)print('结果: ', list(r))
print('x: ', x)
这个代码相当于使用for循环
x = [1, 2, 3]def square(x):return x * x# r = map(square, x)
r = []
for v in x:r.append(square(v))print('结果: ', list(r))
print('x: ', x)
结果是一样的:
结果: [1, 4, 9]
x: [1, 2, 3]
4. map与lambda表达式结合使用
可以简化代码
x = [1, 2, 3]r = map(lambda x: x + x, x)print('结果: ', list(r))
print('x: ', x)
结果:
x = [1, 2, 3]r = map(lambda x: x * x, x)print('结果: ', list(r))
print('x: ', x)
使用多个序列, 需要注意, 后面传入的序列个数和lambda表达式参数个数一直
x = [1, 2, 3]
y = [10, 20, 30, 40]
# 传入x和y两个参数, lambda表示参数个数也是2
r = map(lambda x, y: x * y, x, y)print('结果: ', list(r))
print('x: ', x)
结果:
结果: [10, 40, 90]
x: [1, 2, 3]
返回结果的长度是最小的序列长度
5. reduce函数
from functools import reduce
recude(函数, 序列, 初值)
from functools import reducedef add(x, y):return x + yx = [1, 2, 3]
r = reduce(add, x)
print(r)
结果
6
reduce()
函数运算原理
-
没有初值的情况
第一次执行, 调用add(1, 2), r = add(1, 2)
第二次执行, 调用add(r, 3), r = add(r, 3)
此时, 序列已经执行到最后一个元素了, 返回执行的结果
所以结果是: add(add(1, 2), 3)
-
有初值的情况
第一次执行, 调用add(初值, 2), r = add(初值, 2)第二次执行, 调用add(r, 2), r = add(r, 2)
第三次执行, 调用add(r, 3), r = add(r, 3)
此时, 序列已经执行到最后一个元素了, 返回执行的结果
所以结果是: add(add(add(初值, 1), 2), 3)
from functools import reducedef add(x, y):return x + yx = ['1', '2', '3']
r = reduce(add, x, 'v')
print(r)
结果:
v123
6. filter函数
filter(函数, 序列)
例子: 保留x列表中值大于3的元素
x = [1, 2, 6, 5, 4, 3]def fun(x):return True if x > 3 else Falser = filter(fun, x)print(list(r))
装饰器
1. 引例
现在有三个函数, 在每个函数中都要输出函数调用的时间
import timedef practice():def func1():print(time.time())print('func1')def func2():print(time.time())print('func2')def func3():print(time.time())print('func3')return func1, func2, func3printTime = practice()for i in printTime:i()
结果:
1653194377.809377
func1
1653194377.809377
func2
1653194377.809377
func3
如果此时, 将打印时间改为打印函数名, 是不是需要对每一个函数进行修改?
修改是封闭的, 扩展是开放的, 修改不能解决根本
优化
import timedef practice():def printTime(func):print(time.time())func()def func1():print('func1')def func2():print('func2')def func3():print('func3')return func1, func2, func3, printTimefunc1, func2, func3, printTime = practice()printTime(func1)
printTime(func2)
printTime(func3)
结果:
1653194518.6538224
func1
1653194518.6538224
func2
1653194518.6538224
func3
为了更简便, 这就引入了装饰器
2. 装饰器
import time# 定义装饰器
def decorator(func):def wrapper():print(time.time())func()return wrapperdef func1():print('func1')# 使用装饰器
func1 = decorator(func1)
func1()
看上去, 这种使用跟printTime()
这种方法没什么区别
3. 装饰器使用
使用@
简化调用
使用方法: @装饰器名字
import timedef decorator(func):def wrapper():print(time.time())func()return wrapper@decorator
def func1():print('func1')func1()
结果
1653195433.3289523
func1
4. 对带有参数的函数定义装饰器
对于wrapper()函数
使用可变参数
import timedef decorator(func):def wrapper(*parameters):print(time.time())func(*parameters)return wrapper@decorator
def func1(x):print('func1', x)@decorator
def func2(x, y):print('func1', x, y) func1(1)
func2('aaa', 'bbb')
结果:
1653196573.0688334
func1 1
1653196573.0688334
func1 aaa bbb
这种情况也有问题, 不兼容 **args
参数
import timedef decorator(func):def wrapper(*parameters):print(time.time())func(*parameters)return wrapper@decorator
def func1(**x):print('func1', x)func1(a = 2, b = 3)
会报错
解决办法:
import timedef decorator(func):def wrapper(*parameters, **kwargs):print(time.time())func(*parameters, **kwargs)return wrapper@decorator
def func1(**x):print('func1', x)func1(a = 2, b = 3)
5. 带有参数的装饰器的理解
*parameters
用于获取函数默认的传参顺序所获得的值
**kwargs
用于获取可变参数列表的值
def decorator(func):def wrapper(*parameters, **kwargs):print(parameters)print(kwargs)func(*parameters, **kwargs)return wrapper@decorator
def func1(p1, p2, **x):print('func1', p1, p2, x)func1(1, 2, a = 2, b = 3)
结果:
(1, 2)
{'a': 2, 'b': 3}
func1 1 2 {'a': 2, 'b': 3}
6. 装饰器完整定义
def 装饰器名字(func):def wrapper(*parameters, **kwargs):所要执行的逻辑func(*parameters, **kwargs)return wrapper
使用
@装饰器名称
7. 使用python装饰器保存内置变量的值
from functools import wrapsdef 装饰器名字(func):@wraps(func)def wrapper(*parameters, **kwargs):所要执行的逻辑func(*parameters, **kwargs)return wrapper
8. 数据类装饰器 dataclass
用来简化构造函数赋值
原来的样子
class Student:def __init__(self, name, age):self.name = nameself.age = age
使用修饰器
from dataclasses import dataclass@dataclass
class Student:name: strage: int# def __init__(self, name, age):# self.name = name# self.age = agedef showInfo(self):print(self.name, self.age)student = Student('小米', 18)
student.showInfo()
看一下dataclass函数
def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False,unsafe_hash=False, frozen=False, match_args=True,kw_only=False, slots=False):...
可以看出, 在@dataclass后面可以指定参数
init=True 表示默认产生构造函数
用字典映射代替switch case
C语言中的switch case语句
switch (表达式) {case 整型数值1: 语句 1;case 整型数值2: 语句 2;......case 整型数值n: 语句 n;default: 语句 n+1;
}
python中使用字典
switcher = {值1: 函数1值2: 函数2......值n: 函数n
}r = switcher.get(值, default函数)()
例子: 输入1 ~ 7之间的数字, 输出对应的星期
def isMonday():return '星期一'def isTuesday():return '星期二'def isWednesday():return '星期三'def isThursday():return '星期四'def isFriday():return '星期五'def isSaturday():return '星期一'def isSunday():return '星期天'def default():return '输入错误'switcher = {1: isMonday,2: isTuesday,3: isWednesday,4: isThursday,5: isFriday,6: isSaturday,7: isSunday
}v = input()
r = switcher.get(int(v), default)()
print(r)
列表推导式
列表推导式: 使用列表, 字典, 元组, 集合, 创建一个新的列表, 字典, 元组, 集合
(1). 简单使用
[ 表达式 i for in x ]
def add(x):return x + xx = [1, 2, 3]b = [add(i) for i in x if i == 2]print(b)
结果:
[2, 4, 6]
(2). 带有条件的列表推导式
[ 表达式 i for in x if 表达式 ]
当i满足条件e()时, 执行f(), 将结果放入新的列表中
def add(x):return x + xdef condition(x):return x == 2x = [1, 2, 3]b = [add(i) for i in x if condition(i)]print(b)
结果:
[4]
(3). 使用列表推导式创建元组
def add(x):return x + xdef condition(x):return x >= 2x = [1, 2, 3, 4, 5]b = (add(i) for i in x if condition(i))print(b)
结果:
<generator object <genexpr> at 0x00000134B19F18C0>
此时结果不是元组, 而是一个generator, 遍历一下generator
def add(x):return x + xdef condition(x):return x >= 2x = [1, 2, 3, 4, 5]b = (add(i) for i in x if condition(i))for i in b:print(i)
结果:
4
6
8
10
转换一下可以得到元组
def add(x):return x + xdef condition(x):return x >= 2x = [1, 2, 3, 4, 5]b = tuple((add(i) for i in x if condition(i)))print(b)
结果:
(4, 6, 8, 10)
(4). 字典列表推导式
items()
students = {'张三': 18,'李四': 19,'王五': 21
}s = [key for key, value in students.items()]print(s)
结果:
['张三', '李四', '王五']
需要注意的是, 字典遍历需要使用items()
函数
字典推导字典
将students字典中的key变成value, value变成key
students = {'张三': 18,'李四': 19,'王五': 21
}s = {value: key for key, value in students.items()}print(s)
结果:
{18: '张三', 19: '李四', 21: '王五'}
函数式编程
for i in range(start, end, step = 1):pass
代替
[pass for i in range(start, end, step = 1)]
list(map(lambda i: dosomething, [i for i in range(start, end, step = 1)])
)
迭代器
(1). 可迭代对象 和 迭代器
可迭代对象: 可以使用for-in循环遍历的对象
迭代器: 是一个类, 可以被for-in循环遍历
(2). 自定义迭代器
类实现两个函数, __iter__()
和 __next__()
def __iter__(self):passdef __next__(self):pass
例子:
class BookCollection:def __init__(self):self.data = ['1', '2', '3']self.cur = 0def __iter__(self):return selfdef __next__(self):if self.cur >= len(self.data):self.cur = 0raise StopIteration()r = self.data[self.cur]self.cur += 1return rbooks = BookCollection()
[print(i) for i in books]
结果:
1
2
3
生成器
生成器是针对函数的, 保存一个算法
def generate(end):n = 0while n < end:n += 1yield nprint(generate(100))
使用列表推导式得到生成器
print(i for i in range(1, 9))
海象运算符 :=
可以使用在if中, 使得函数调用的值赋给一个变量, 同时进行条件判断操作, 省去了在外定义变量
a = "Python"if l := len(a) > 5:print(l)
结果:
6
使用前:
a = "Python"
l = len(a)
if l > 5:print(l)
相关文章:

python学到什么程度算入门,python从入门到精通好吗
本篇文章给大家谈谈python学到什么程度算入门,以及python从入门到精通好吗,希望对各位有所帮助,不要忘了收藏本站喔。 学习 Python 之 进阶学习 一切皆对象 1. 变量和函数皆对象2. 模块和类皆对象3. 对象的基本操作 (1). 可以赋值给变量(2). …...

整数规划——第一章 引言
整数规划——第一章 引言 整数规划是带整数变量的最优化问题,即最大化或最小化一个全部或部分变量为整数的多元函数受约束于一组等式和不等式条件的最优化问题。许多经济、管理、交通、通信和工程中的最优化问题都可以用整数规划来建模。 考虑一个电视机工厂的生产…...

C语言结构体讲解
目录 结构体的声明 结构的基础知识 结构的声明 为什么要出现结构体? 结构成员的类型 结构体变量的定义和初始化 定义:(全局变量//局部变量) 初始化: 结构体成员的访问 结构体传参 结构体的声明 结构的基础知识…...

021 - STM32学习笔记 - Fatfs文件系统(三) - 细化与总结
021 - STM32学习笔记 - Fatfs文件系统(三) - 细化与总结 上节内容中,初步实现了FatFs文件系统的移植,并且实现了设备的挂载、文件打开/关闭与读写功能,这里对上节遗留的一些问题进行总结,并且继续完善文件…...

jQuery如何获取动态添加的元素
jQuery如何获取动态添加的元素 使用 on()方法 本质上使用了事件委派,将事件委派在父元素身上 自 jQuery 版本 1.7 起,on() 方法是 bind()、live() 和 delegate() 方法的新的替代品,但是由于on()方法必须有事件,没有事件时可选择de…...

Keepalived 在CentOS 7安装并配置监听MySQL双主
keepalived安装 MySQL双主配置请看这里:https://tongyao.blog.csdn.net/article/details/132016200?spm1001.2014.3001.5502 128、129两台服务器安装步骤相同,配置文件不同,下面有介绍。 1.安装相关依赖包,并下载keepalived安…...

深度学习,神经网络介绍
目录 1.神经网络的整体构架 2.神经网络架构细节 3.正则化与激活函数 4.神经网络过拟合解决方法 1.神经网络的整体构架 ConvNetJS demo: Classify toy 2D data 我们可以看看这个神经网络的网站,可以用来学习。 神经网络的整体构架如下1: 感知器&…...

中国AI大模型峰会“封神之作”!开发者不容错过这场夏季盛会
年度最强大模型顶会来袭!喊话中国数百万AI开发者,速来! 硬核来袭!中国AI大模型峰会“封神之作”,开发者们不容错过! 前瞻大模型发展趋势,紧跟这场大会! 中国科技超级碗,大模型最新前…...

Android Studio多渠道打包
使用环境: Android studio 多渠道打包 使用方法: 1 APP下build.gradle文件 flavorDimensions "default"productFlavors {huawei {dimension "default"manifestPlaceholders [ channel:"huawei" ]}xiaomi {dimension &…...
RK3566 Android11默认客户Launcher修改
前言 客户需要默认自己的Launcher为home,同时保留系统的Launcher3. 解决办法:在启动home应用之前设置一下默认Launcher。查找home app启动相关资料,找到了frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java的startHomeOnTaskDisplayA…...

ORB算法在opencv中实现方法
在OPenCV中实现ORB算法,使用的是: 1.实例化ORB orb cv.xfeatures2d.orb_create(nfeatures)参数: nfeatures: 特征点的最大数量 2.利用orb.detectAndCompute()检测关键点并计算 kp,des orb.detectAndCompute(gray,None)参数:…...
vue项目回显文本无法识别换行符
解决方法 1:使用<br/>替换文本中的\n,使用v-html渲染 <template> <div v-html"str"></div> </template> <script> let str 以下内容自动换行\n换行了 // 使用replace截取提换 this.str str.replace(/…...

Minio 部署
minio 官网:https://www.minio.org.cn/ 部署文档:https://www.minio.org.cn/docs/minio/container/operations/install-deploy-manage/deploy-minio-single-node-single-drive.html# 选择自己的部署环境: 我用的docker: docker pull qua…...

Kafka系列之:记录一次Kafka Topic分区扩容,但是下游flink消费者没有自动消费新的分区的解决方法
Kafka系列之:记录一次Kafka Topic分区扩容,但是下游flink消费者没有自动消费新的分区的解决方法 一、背景二、解决方法三、实现自动发现新的分区一、背景 生产环境Kafka集群压力大,Topic读写压力大,消费的lag比较大,因此通过扩容Topic的分区,增大Topic的读写性能理论上下…...
Ansible部署MariaDB galera集群(多主)
文章目录 Ansible部署MariaDB galera集群(多主)介绍节点规划基础环境准备编写剧本文件执行剧本文件查看集群状态测试 Ansible部署MariaDB galera集群(多主) 介绍 MariaDB Galera集群是一套基于同步复制的、多主的MySQL集群解决方案,使用节点没有单点故障ÿ…...
立体库-库龄
split 用法第一种: 1.对单个字符进行分割(注意这里是字符,不是字符串,故只能用单引号‘’) string sabcdeabcdeabcde; string[] sArrays.Split(c) ; foreach(string i in sArray) Console.WriteLine(i.ToString());…...
extern/头文件包含,实现一个函数被两个文件共用
目录 一、extern 1、在a.c文件中定义int add函数 2、在b.c文件中使用extern关键字声明add函数 二、用头文件包含的形式 1、在a.c文件中定义int add函数 2、创建一个名为a.h的头文件,其中包含add函数的函数原型 3、在b.c文件中包含a.c的头文件,并调…...

pgsql 查看某个表建立了那些索引sql
执行以下sql: SELECTns.nspname as schema_name,tab.relname as table_name,cls.relname as index_name,am.amname as index_type,idx.indisprimary as is_primary,idx.indisunique as is_unique FROMpg_index idx INNER JOIN pg_class cls ON cls.oididx.indexrel…...

【SCSS】网格布局中的动画
效果 index.html <!DOCTYPE html> <html><head><title> Document </title><link type"text/css" rel"styleSheet" href"index.css" /></head><body><div class"container">&l…...

Docker基础命令(一)
Docker使用1 一、运行终端 打开终端,输入docker images ,如果运行正常,表示docker已经可以在本电脑上使用了 二、docker常用命令 指令说明docker images查看已下载的镜像docker rmi 镜像名称:标签名删除已下载的镜像docker search 镜像从官…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...