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

python基础篇--学习记录2

1.深浅拷贝

l1 = ["张大仙","徐凤年",["李淳刚","邓太阿"]]
# 变量名对应的就是内存地址,这里就是将l1的内存地址给了l2
# 现在两个变量指向同一个内存地址,l1变化l2也会变化
l2 = l1

现在的需求是l2是l1的拷贝版本,但是两者是完全分割开来的,l2修改之后不能影响我l1的数据

1.1 浅拷贝

l3 = l1.copy()

l1和l3 列表的id不一样但是里面存储内容的id却是一样的
拷贝的列表只是拷贝的容器本身,只是产生了一个新的容器,但是里面的数据还是原来的数据

l1 = ["张大仙", "徐凤年", ["李淳刚", "邓太阿"]]
# 变量名对应的就是内存地址,这里就是将l1的内存地址给了l2
# 现在两个变量指向同一个内存地址,l1变化l2也会变化
# l2 = l1l3 = l1.copy()print(l1, id(l1))  # ['张大仙', '徐凤年', ['李淳刚', '邓太阿']] 4553523080
print(l3, id(l3))  # ['张大仙', '徐凤年', ['李淳刚', '邓太阿']] 4555309832
print(id(l1[0]), id(l1[1]), id(l1[2]))  # 4353425648 4354327536 4353425224
print(id(l3[0]), id(l3[1]), id(l3[2]))  # 4353425648 4354327536 4353425224

浅拷贝后,发现l3确实被改变了,但是l1的子列表也发生了变化 

l1 = ["张大仙", "徐凤年", ["李淳刚", "邓太阿"]]
l3 = l1.copy()
l3[0] = "张坦克"
l3[1] = "徐晓"
l3[2][0] = "小明"
l3[2][1] = "小李"
print(l1)  # ['张大仙', '徐凤年', ['小明', '小李']]
print(l3)  # ['张坦克', '徐晓', ['小明', '小李']]

因为浅拷贝只会将原列表的第一层里面的索引和内存地址一模一样的拷贝到新的内存空间里面,由于列表里面的第一个和第二个元素是字符串,不可变类型,所以修改l3时,又会申请新的内存空间.但是由于列表是可变类型,我们修改其子列表的时候,它的内存地址是不会变的.所以l1和l3里面存的还是原来的子列表的内存地址,但是子列表的数据却被改掉了.

浅拷贝会把原列表第一层存的索引和内存地址完全拷贝一份给新的列表,如果原列表存储的都是不可变类型,浅拷贝就可以正常使用,新列表改动之后就会产生新的值,不会影响原来的列表.但是一旦包含了可变类型浅拷贝的原列表就没办法和原列表完全分开.

1.2 深拷贝

深拷贝针对不可变对象,第一层的索引和内存地址是一模一样的,但是对于可变对象,深拷贝会产生一个新的内存地址,但是还是使用的是原来的值

深拷贝针对可变类型会产生新的容器,可对不可变类型则是仍然使用原值

l1 = ["张大仙", "徐凤年", ["李淳刚", "邓太阿"]]
import copyl3 = copy.deepcopy(l1)print(l1, id(l1))  # ['张大仙', '徐凤年', ['李淳刚', '邓太阿']] 4325347208
print(l3, id(l3))  # ['张大仙', '徐凤年', ['李淳刚', '邓太阿']] 4327146568print(id(l1[0]), id(l1[1]), id(l1[2]))  # 4479013104 4479914992 4479012680
print(id(l3[0]), id(l3[1]), id(l3[2]))  # 4479013104 4479914992 4480805448
print(id(l1[2][0]), id(l1[2][1]))  # 4470445136 4470445232
print(id(l3[2][0]), id(l3[2][1]))  # 4470445136 4470445232l3[0] = "张坦克"
l3[1] = "徐晓"
l3[2][0] = "小明"
l3[2][1] = "小李"print(l1)  # ['张大仙', '徐凤年', ['李淳刚', '邓太阿']]
print(l3)  # ['张坦克', '徐晓', ['小明', '小李']]

2.变量

2.0 储存

我们在定义一个变量的时候,它有两部分需要储存.一部分是变量名,一部分是变量值.在内存里面也是对应两块内存空间栈区是专门用来存放变量名的,堆区则是专门用来存放变量值的当定义一个name="张大仙"的时候,会先在堆区里面申请一块内存空间,把值张大仙存储进去.对应一个内存地址.在栈区里面放一个name,对应上刚刚的内存地址.当堆区的内存地址引用计数为0被清除的时候,对应栈区的变量名也会被清除

2.1 内存管理

定义变量就是在内存里面开辟了一个内存空间,然后将一个空间的内存地址捆绑给了变量名,通过这个变量名,我们就可以找到这个对应的值在哪.我们知道定义变量是要占用内存空间的,但是内存空间的大小是有限的.这时候就有一个问题,就是你申请的内存空间,不用了一定要及时的释放出来.否则的话,你将内存撑爆了的话就会导致内存溢出的问题,这个操作就叫做内存管理.

而python推出了一个内存管理机制,被叫做"垃圾回收机制",垃圾回收机制就是用来回收这种没有关联任何变量名的值.而这也涉及到一个概念叫做"引用计数",也就是一个内存空间身上捆绑了几个变量名.引用计数变为0的时候它就是一个垃圾

2.2 垃圾回收机制

2.2.1 引用计数的增加

a =100

申请一个内存空间将100 存进去,然后给这个内存空间绑定一个变量名叫a,a指向的就是100的内存地址

b = a

将a的内存地址给b,这时候a和b指向的就是同一个内存地址

c = a

现在 a b c指向的都是同一个内存地址

2.2.2  引用计数的减少

 del a

表面上看是删除a,实际上是解除a与100身上的绑定关系 

a = 100
b = a
c = a
del a
print(a)
del b
c = 123 # c会和100的绑定关系解除,重新指向123的内存地址

2.3 变量值特征

1) id: 根据变量值的内存地址所计算出来的一个id号码,类似于内存地址的映射.变量值的内存地址不一样,id就会不一样

2) type:查看变量值的类型

2.4 is和==的区别

1) is叫做身份运算,是用来比较左右两个值的身份是否相等的,而变量值的身份证号就是id号,所以is就是用来比较两个变量值的id是否相等的

2) == 是用来比较左右变量的值是否是相等的

将代码直接使用python解释器来运行 

所以只要是赋值操作,产生新的值的时候,都会申请一块新的内存空间,只要是申请了新的内存空间,它的内存地址就会不一样,id就会不一样.

2.5 小整数池的概念

申请内存空间将值存进去,这就是一种写操作,IO操作,不管是往硬盘里面读写还是往内存读写数据,这都是IO操作.这都是耗时的,python给我们做了优化,叫做小整数池.为了避免因创建相同的值,而重复申请内存空间带来的效率问题,python解释器会在启动的那一刻创建出小整数池(-5,256).就是python解释器一启动就立刻申请一堆内存空间,把这些值放进去,这个范围内的整数被重复使用时就不会再申请新的内存空间,而且这些小整数也永远不会被垃圾回收机制回收.

3. 列表在内存中的存储方式

直接引用:创建内存空间,将数值放进去,变量名直接指向内存地址

间接引用:列表是间接引用

开辟内存空间,存一个0号索引,对应值a的内存地址;1号索引,对应值b的内存地址;2号索引,对应值c的内存地址;a的内存地址再指向一个内存空间里面存放的才是a这个值,b,c同理.也就是说列表不会存放真正的值,只会存放索引和值的内存地址.而值会存放在单独的内存空间

4 内存管理

4.1 循环引用之内存泄露问题

前面说过不管是直接引用还是间接引用,只要引用计数为0时,它就会被垃圾回收机制回收.但是这种工作方式是有问题的

# _*_ coding utf-8 _*_
# george
# time: 2024/3/7上午9:21
# name: store.py
# comment:
l1 = ["a", "b"]
l2 = ["x", "y"]
l1.append(l2)
print(id(l2), id(l1[2]))  # 4410818440 4410818440
l2.append(l1)
print(l2)  # ['x', 'y', ['a', 'b', [...]]]
print(id(l1), id(l2[2]))  # 4355399496 4355399496
"""
现在l1存储了l2的内存地址,l2也存储了l1的内存地址,这两个列表中存在一种相互引用的关系,也就是循环引用.
循环引用会导致非常致命的问题
我现在解除了l1,l2的直接引用,但是他们的引用计数并没有变为0,它们身上只有他们相互之间的间接引用,我们再也没办法取到这两个表
垃圾回收机制会回收引用计数为0的内存空间,但是这两个列表变成了永远回收不了的垃圾,永远占据这两个内存空间,这就叫内存泄露
"""
del l1
del l2
print(l1,l2) # NameError: name 'l1' is not defined

现在l1存储了l2的内存地址,l2也存储了l1的内存地址,这两个列表中存在一种相互引用的关系,也就是循环引用.

循环引用会导致非常致命的问题 我现在解除了l1,l2的直接引用,但是他们的引用计数并没有变为0,它们身上只有他们相互之间的间接引用,我们再也没办法取到这两个表 垃圾回收机制会回收引用计数为0的内存空间,但是这两个列表变成了永远回收不了的垃圾,永远占据这两个内存空间,这就叫内存泄露.而循环引用就会导致内存泄露问题.python提供了一个补充解决方法叫做标记清除.

4.2 标记清除机制

标记清除会在python程序内存空间不够用的时候,将整个程序暂停下来,扫描栈区.把通过栈区所能够引用到的值不管是直接引用还是间接引用到的,全都标记为存活状态.一旦发现有通过栈区引用不到的值,都标记为死亡状态.死亡状态的值会被直接清理掉.就算它身上的引用计数不为0,只要我们访问不到它了,标记清除就会将它标记为垃圾,然后回收掉.

4.3 分代回收机制

前面说的引用计数和标记清除已经可以实现回收所有的垃圾了.但是现在垃圾回收机制还是有一个弊端.就是基于引用计数的垃圾回收机制,每次回收内存都需要把所有对象的引用计数全部都遍历一遍.当我们申请的变量很多的时候,每次都要将所有的变量全都扫描一边,这样的效率是非常低的.

分代回收机制的核心是:对象存在的时间越长,是垃圾的可能性就越小,应该尽量不对这样的对象进行垃圾回收。CPython将对象分为三种世代分别记为0、1、2,每一个新生对象都在第0代中,如果该对象在一轮垃圾回收扫描中存活下来,那么它将被移到第1代中,存在于第1代的对象将较少的被垃圾回收扫描到;如果在对第1代进行垃圾回收扫描时,这个对象又存活下来,那么它将被移至第2代中,在那里它被垃圾回收扫描的次数将会更少。

垃圾回收机制主要是引用计数来扫描并且回收垃圾,用标记清除解决引用计数回收不了的垃圾,用分代回收解决引用计数扫描效率的问题

5.可变与不可变类型

可变类型

值改变的情况下,id不变,说明改变的是原值,这里的值指的是堆区里面的内容.

列表,字典,集合这种容器类型都是可变类型

不可变类型

值改变的情况下下,id也发生了变化

所有的赋值操作都会申请新的内存空间,产生新的值

整型,浮点型,字符串,布尔值类型,元组

6.函数

6.1 函数的定义和调用

函数需要先定义,再调用

定义函数会申请内存空间,将函数的子代码存进去,然后将这个内存地址绑定给函数名,所以说函数名指向的就是函数的内存地址.并且在定义阶段,不会执行函数的子代码,必须要调用函数才会执行.

函数的定义阶段: 不会执行函数的子代码,但是会检测函数子代码的语法

函数的调用阶段,调用其实背后做了两件事情1)通过函数名找到函数的内存地址,在函数的内存地址后面加上(),触发函数子代码的运行 

 函数的定义阶段只会检测语法,不会执行代码.func1是没有语法错误的,func2的语法也是没有错误的
定义函数就是开辟内存空间,把函数子代码丢到内存空间里面去,然后将函数地址绑定给函数名.
1) 所以此时func1的子代码已经被放进了内存里,并且内存地址绑定给了func1
2) 检测func2也没有语法错误,func2的代码也丢到了内存里面,同时内存地址也绑定给了func2
到现在还没有执行任何函数子代码,但是内存里面已经存在了func1和func2的子代码
所以此时调用func1就不会报错

将函数的调用作为函数的参数来使用,本质上其实是将函数的返回值作为参数使用.

6.2 return

return就是函数结束的标志,只要函数子代码遇到return,就会立刻结束函数的运行,并且将return后面的值当做本次运行结果返回.如果我们返回多个值,就会被处理成为元祖

6.3 参数

函数的参数从定义阶段和调用阶段可以分为两部分

定义阶段:形式参数,简称形参

调用阶段:实际参数,简称实参

形参和实参在定义阶段是没有任何关系的,只有在调用阶段,实参才会绑定给形参,就是变量值绑定给变量名(变量值的内存地址,绑定给了变量名)

6.3.1 位置参数

位置参数就是按照从左到右的顺序,依次定义的参数.

位置形参:定义函数的时候,从左到右.依次定义的形参.必须传值,不能多也不能少

位置实参:在调用函数的时候,从左往右依次传入的值

def func(x, y, z):print(x, y, z)func(1, 2, 3) # 1 2 3

6.3.2 关键字参数(关键字实参)

可以不按照顺序,而是以key=value的形式进行传值,key必须是定义函数的时候指定好的形参名

def func(x, y, z):print(x, y, z)#  位置实参
# func(1, 2, 3)  # 1 2 3# 关键字实参
func(z=3, x=1, y=2)  # 1 2 3

关键字实参和位置实参进行混用,但是必须遵循一个原则:位置实参一定要放在关键字实参之前

def func(x, y, z):print(x, y, z)#  位置实参
# func(1, 2, 3)  # 1 2 3# 关键字实参
# func(z=3, x=1, y=2)  # 1 2 3# 混用
func(1, 2, z=3)  # 1 2 3
func(x=1, 2, 3)  # SyntaxError: positional argument follows keyword argument

6.3.4 默认参数(默认形参)

在定义阶段,就为其赋了默认值的形参.定义默认形参就意味着,在调用函数的时候可以不用为其传值.

定义的时候,默认形参必须放在位置形参之后

# 默认形参
def func(x, y=2):print(x, y)func(2)  # 2 2
func(1, 3)  # 1 3

默认参数的值是在函数定义阶段被赋值的

# 默认形参
a = 2def func(x, y=a):  # 其实就是y指向2的内存地址,3指向a的内存地址print(x, y)a = 3
func(1)  # 1 2
a = [2, 3]def func(x, y=a):  # y指向[2,3]的内存地址print(x, y)a.append(4)  # 列表为可变数据类型,增加值时,内存地址不改变
func(1)  # => 1 [2, 3, 4]

python里面所有的值的传递,都是内存地址的传递,内存地址是对值的引用.

python里面所有的值传递,都是引用传递

虽然函数默认参数的值可以指定成为任意类型数据,但是不建议指定成为可变类型.因为一个函数的输出结果最好,只和函数的调用和函数的本身有关系.就是我传递什么参数,调用时就会得到什么结果,不会受到外界代码的影响.

# 之前说过尽量不要将默认形参的值设置成可变类型,虽然现在定义的形参不能被外界改变,用起来也没有问题
# 但是从规范层面上面来说我们不应该这么做
def my_append(x, y, l=[]):l.append(x)l.append(y)print(l)l = [3,4]
my_append(1,2,[3,4]) # [3, 4, 1, 2]
def my_append(x, y, l=None):if l is None:  # 因为None也是小整数池里面的,None指向的都是同一个内存地址l = []l.append(x)l.append(y)print(l)l = [3, 4]
my_append(1, 2, [3, 4])  # => [3, 4, 1, 2]

6.3.4 可变长参数

可变长参数是指在调用函数的时候,传入的参数个数是不固定的

6.3.4.1 可变长度的位置参数

用法: *形参名,形参名就可以用来接收多出来的位置实参

*在形参中

# 可变长度的位置参数
def func(x, y, *z):  # 将*处理成为元祖,然后赋值给z,z=(3,4,5)print(x, y, z)func(1, 2, 3, 4, 5)  # => 1 2 (3, 4, 5)
# 求和
def func(*args):sum = 0for i in args:sum += ireturn sumres = func(1, 2, 3, 4)
print(res)  # => 10
res1 = func(1, 2, 3, 4, 5)
print(res1)  # => 15

* 在实参 

def func(x, y, z):print(x, y, z)# *会将后面的多个值打散,打散成为位置实参,相当于func(1,2,3)
func(*[1, 2, 3])  # => 1 2 3

*在形参中表示可变长度的位置参数,它会把多个值处理成为元祖.然后赋值给后面的形参名.

*在实参中间有打散的作用,打散成为位置实参

*在形参中也在实参中

def func(x, y, *args):print(x, y, args)func(*"愿疫情早点结束!")  # 愿 疫 ('情', '早', '点', '结', '束', '!')
  6.3.4.2 可变长度的关键字参数

用法:**kwargs,它就是用于接收多出来的关键字实参的,**会将多出来的关键字实参处理成字典格式.然后赋值给**后面的形参名

无论是*还是**,都是用来接收溢出的实参的,所以一定要放在参数的最后,放在位置形参和默认形参之后

def func(x, y, **kwargs):  # kwargs={'a': 3, 'b': 4, 'c': 5, 'name': '张大仙'}print(x, y, kwargs)  # => 1 2 {'a': 3, 'b': 4, 'c': 5, 'name': '张大仙'}func(x=1, y=2, a=3, b=4, c=5, name="张大仙")

**在形参中表示可变长度的关键字参数,它会把多个值处理成为字典.然后赋值给后面的形参名.

**在实参中间有打散的作用,打散成为关键字实参

def func(x, y, z):print(x, y, z) # 1 2 3func(**{"x":1,"y":2,"z":3}) # => func(x=1,y=2,z=3)
def func(x, y, **kwargs):print(x, y, kwargs)  # => 1 2 {'z': 3}func(**{"x": 1, "y": 2, "z": 3})  # 等价于 func(x=1,y=2,z=3)

6.3.5 可变参数混用

我们调用函数进行传参的时候,有多出来的位置实参,也有多出来的关键字实参,这个时候就涉及到*和**的混用.而此时**kwargs必须在*args之后 

def func(x, y=1, *args, **kwargs):print(args)  # => (1, 2, 3, 4)print(kwargs)  # => {'a': 1, 'b': 2, 'c': 3}func(1, 2, 1, 2, 3, 4, a=1, b=2, c=3)

6.3.6 命名关键字形参(命名关键字参数)

pass

6.4 函数重中之重

def func1(x, y, z, s):print("func1>>", x, y, z, s)# 这样就将传递给func2的参数,原封不动的传递给了func1
def func2(*args, **kwargs):  # args=(1,2,3,4)func1(*args, **kwargs)  # func1(1,2,3,4)func2(1, 2, 3, 4)  # => func1>> 1 2 3 4

6.5 名称空间和作用域

名称空间就是用来存名字的.

我们定义x=5,在内存里面就涉及到两个空间,栈区和堆区.首先会在堆区里面申请一个名称空间将5存进去.并将这个内存地址绑定给栈区里面的变量名x.栈区里面就是存储名字的

名称空间其实是将栈区里面的名字做了一个分类,或者说是将栈区里面的名字分成了几块:内置名称空间,全局名称空间,局部名称空间.当栈区里面有了名称空间之后,栈区里面分成了不同的区域,不同区域里面存储相同的变量名称也不会发生冲突.

作用域:

在名称空间的基础上,按照作用范围的不同,将它们重新做了分类.内置名称空间和全局名称空间都被归为全局作用域,局部名称空间被归为局部作用域.

6.5.1 内置名称空间

存放python解释器内置名字的地方,内置名称空间只有一个内置名称空间,也就是说python解释器一启动就会创建内置名称空间.,让我们可以在任何位置使用内置名称空间里面的名字.python解释器关闭,内置的名称空间就会被销毁.

运行python程序有三个阶段

1)python解释器启动: 产生内置的名字

2)python解释器将文件内容,当做普通文本内容读入到内存.

3)识别python语法,运行代码,产生变量名产生函数名产生模块名  

6.5.2 全局名称空间

全局名称空间:Python文件内定义的变量名,包括函数名,类名,以及导入的模块名.既然python里面定义的名字是存放在全局名称空间里面的,那么就是说有多个pyhton文件就会有多个全局名称空间.全局名称空间可以有多个.但是这里要排除掉函数内部定义的名字(包括函数参数)

只要不是函数内部定义的名字,也不是内置的名字,剩下的都是全局名称空间里面的名字

全局名称空间它会在python文件执行之前产生,python文件运行完毕后销毁

6.5.3 局部名称空间

函数内部定义的名字(包括函数参数)

而局部名称空间会在函数调用时产生,就是运行函数子代码的时候产生,函数调用结束后销毁.局部名称空间也可以有很多个,调用一个产生一个.

名称空间加载顺序:

python解释器启动会加载内置名称空间,python解释器将文件内容,当做普通文本内容读入到内存.然后加载全局名称空间.加载完毕,识别python语法执行代码.调用函数产生名称空间

6.6 名字查找顺序

有了名称空间之后,不同名称空间的相同名字是不会相互影响的,但是名称空间的查找优先级?

局部名称空间>全局名称空间>内置名称空间

def func():print(x)x = 10
func()  # => 10

加载内置名称空间->加载全局名称空间->将func丢入全局(函数在定义阶段只会检测语法,不会执行函数子代码)将x=10丢入全局,调用func时,全局存在x.

x = 10def func1():print(x)def func2():# print(x)x = 20func1()func2() # => 10

名称空间的查找顺序是以定义阶段为基准的,和调用的位置没有任何关系

6.7 函数的嵌套

名字的查找是以定义阶段为基准的

6.8 作用域 

作用域是将名称空间做了一个分类

全局作用域:内置名称空间+全局名称空间

1)全局存活,就是整个程序运行过程中它都是存活状态

2)全局有效,全局里面的名字是共享的

局部作用域:局部名称空间

1)临时存活,函数调用的时候就活了,函数调用完立马死

2)局部有效

名称空间本质上面只有三种,但是为了方便记忆,将名称空间分为了四种:LEGB,将局部名称空间分为了两类,就是针对函数嵌套的情况,因为名称空间嵌套在一起时,都被叫做局部名称空间不好区分.

B: built-in(内置)

G:global(全局),修改G里面的变量使用global声明

E:enclosing(封闭),修改E里面的变量用nonlocal声明

L:local(本地):并不是说最里面那层函数就是local,从哪里开始找,哪里就是local

"""
先从func3找x,在func3的内部也被叫做local
如果local里面没有,就去上一层找,上一层叫做enclosing
func1的局部也叫做enclosing,就是local外面套的局部名称空间都可以做enclosing
"""# 内置 build-in
# 全局 global
def func1():# enclosingdef func2():# enclosingdef func3():# localprint(x)

以后找变量名就可以说是现在local找,local没有就去enclosing找,enclosing里面没有就去global里面找,global里面没有就去built-in里面找.其实本质的查找顺序并没有发生变化,只是叫法不同而已.

6.9 global

在函数的内部修改全局的变量.使用global.当然这只是针对不不可变类型,如果是可变类型的话就不需要声明.

6.10 nonlocal 

nonlocal就是说接下来不会在本地创建名字了,也不会修改全局的名字,而是修改local上一层局部的名字.如果上一层E没有,就到再上一层E中找,如果所有的E都没有的话,就会直接报错,它并不会去全局找.

# 现在的需求是func2里面的30,修改的是func1里面的x=20
x = 10
def func1():x = 20def func2():nonlocal xx =30print("调用前的x:",x)func2()print("调用后的x:", x)func1()
print("全局的x:",x)

 

7.递归

函数的嵌套有两种:

1) 在定义的时候嵌套:装饰器

2) 在调用的时候嵌套:递归

递归就是调用一个函数的过程中,又调用到了自己本身这个函数 .

函数调用第一次没有结束,就开始了第二次,第二次没结束就开始了第三次......每一次调用都无法结束.但是python不允许出现无休止的递归调用.单纯的死循环,不会无休止的申请内存资源.但是函数每调用一次就会申请一次局部名称空间,而这个局部名称空间只有在函数结束调用的时候,才会被回收.所以就会无休止的产生新的局部名称空间,这样的话我们内存会被撑爆.python对递归的层级做了限制,默认为1000层.

递归本质上就是一个循环 ,除了while循环和for循环之外的循坏.我们只要进入了下一层递归,上一层的内存资源都不会被回收,所以我们一定要给递归设置结束条件,只要满足条件就不会进入下一次递归调用.

相关文章:

python基础篇--学习记录2

1.深浅拷贝 l1 ["张大仙","徐凤年",["李淳刚","邓太阿"]] # 变量名对应的就是内存地址,这里就是将l1的内存地址给了l2 # 现在两个变量指向同一个内存地址,l1变化l2也会变化 l2 l1 现在的需求是l2是l1的拷贝版本,但是两者是完全分割…...

自动化运维工具Ansible

一.Ansible基本内容 1.定义 Ansible是基于模块工作的,只是提供了一种运行框架,本身没有完成任务的能力,真正操作的是Anisble的模块。每个模块都是独立的、实现了批量系统配置、批量程序部署、批量运行命令等功能。 2.特点与优势 优势&…...

VR全景在智慧园区中的应用

VR全景如今以及广泛的应用于生产制造业、零售、展厅、房产等领域,如今720云VR全景更是在智慧园区的建设中,以其独特的优势,发挥着越来越重要的作用。VR全景作为打造智慧园区的重要角色和呈现方式已经受到了越来越多智慧园区企业的选择和应用。…...

用信号的方式回收僵尸进程

当子进程退出后,会给父进程发送一个17号SIGCHLD信号,父进程接收到17号信号后,进入信号处理函数调用waitpid函数回收僵尸进程若多个子进程同时退出后,这是切回到父进程,此时父进程只会处理一个17号信号,其他…...

计算机服务器中了locked勒索病毒怎么解密,locked勒索病毒解密流程

科技的发展带动了企业生产,越来越多的企业开始利用计算机服务器办公,为企业的生产运营提供了极大便利,但随之而来的网络安全威胁也引起了众多企业的关注。近日,云天数据恢复中心接到许多企业的求助,企业的计算机服务器…...

【C语言刷题】——初识位操作符

【C语言刷题】——初识位操作符 位操作符介绍题一、 不创建临时变量(第三个变量),实现两个数的交换(1)法一(2)法二 题二、 求一个数存储在内存中的二进制中“一”的个数(1&#xff0…...

Python 对Excel工作表中的数据进行排序

在Excel中,排序是整理数据的一种重要方式,它可以让你更好地理解数据,并为进一步的分析和报告做好准备。本文将介绍如何使用第三方库Spire.XLS for Python通过Python来对Excel中的数据进行排序。包含以下三种排序方法示例: 按数值…...

Python对头发二维建模(考虑风力、重力)

目录 一、背景 二、代码 一、背景 数值方法被用于创建电影、游戏或其他媒体中的计算机图形。例如,生成“逼真”的烟雾、水或爆炸等动画。本文内容是对头发的模拟,要求考虑重力、风力的影响。 假设: 1、人的头部是一个半径为10厘米的球体。…...

Python基础快速入门

Python基础快速入门 前置知识 Python Python是一种广泛使用的高级编程语言,以其易于学习和使用的语法而闻名。以下是Python的一些主要特点: 高级语言:Python是一种高级语言,这意味着它提供了较高层次的抽象,使编程更…...

C++的学习

代码练习 输入一个字符串&#xff0c;统计其中大写字母、小写字母、数字、空格以及其他字符的个数 #include <iostream>using namespace std;int main() {cout << "请输入一个字符串" << endl;string str;getline(cin,str);int capital 0;int l…...

工地安全反光衣穿戴监测报警摄像机

工地安全反光衣穿戴监测报警摄像机是为了提高工地施工人员的安全意识和监管效率而设计的。这种设备结合了反光衣、监测系统和报警摄像机的功能&#xff0c;可以有效减少工地事故的发生。 首先&#xff0c;工地安全反光衣是一种具有高度可见度的服装&#xff0c;能够使穿戴者在夜…...

UNIAPP微信小程序中使用Base64编解码原理分析和算法实现

为何要加上UNIAPP及微信小程序&#xff0c;可能是想让检索的翻围更广把。&#x1f607; Base64的JS原生编解码在uni的JS引擎中并不能直接使用&#xff0c;因此需要手写一个原生的Base64编解码器。正好项目中遇到此问题&#xff0c;需要通过URLLink进行小程序跳转并携带Base64参…...

人工智能|机器学习——K-means系列聚类算法k-means/ k-modes/ k-prototypes/ ......(划分聚类)

1.k-means聚类 1.1.算法简介 K-Means算法又称K均值算法&#xff0c;属于聚类&#xff08;clustering&#xff09;算法的一种&#xff0c;是应用最广泛的聚类算法之一。所谓聚类&#xff0c;即根据相似性原则&#xff0c;将具有较高相似度的数据对象划分至同一类簇&#xff0c;…...

注意力、自注意力和多头注意力的区别

本文作者&#xff1a; slience_me 注意力、自注意力和多头注意力的区别 理解注意力&#xff08;Attention&#xff09;、自注意力&#xff08;Self-Attention&#xff09;和多头注意力&#xff08;Multi-Head Attention&#xff09;之间的区别非常重要&#xff0c;因为它们是自…...

FTP,SFTP,FTPS,SSL,TSL简介,区别,联系,使用场景说明

文章目录 简介FTPFTPSSFTP加密场景选择FTPS还是SFTPFTP、SFTP、FTPS区别、联系和具体使用场景如何使用FTP、SFTP和FTPSSSLTLSSSL和TLS区别和联系&#xff0c;以及使用场景SSL和TLS技术上的区别一些问题隐式的TLS&#xff08;FTPS/SSL&#xff09;或者显式的TLS&#xff08;FTPS…...

路由算法与路由协议

路由选择协议的核心是路由算法&#xff0c;即需要何种算法来获得路由表中的各个项目。 路由算法的目的很简单&#xff1a;给定一组路由器以及连接路由器的链路&#xff0c;路由算法要找到一条从源路由器到目标路由器的最佳路径。通常&#xff0c;最佳路径是指具有最低费用的路…...

dubbo接口自动化用例性能优化

前言 去年换了一个新部门&#xff0c;看了下当前的自动化用例的情况&#xff0c;发现存在三类性能问题&#xff1a; 本地调试运行时等待时间较长&#xff0c;就算是一个简单的case&#xff0c;执行时间都需要1分钟以上单用例执行时间比较长&#xff0c;部分用例执行时间超过2…...

.net core框架

ASP.NET Core 入门 跨平台开源框架 B/S 类与方法 Console 部分称为“类”。 类“拥有”方法&#xff1b;或者可以说方法存在于类中。 WriteLine() 部分称为“方法”。 想要使用方法就要知道方法在哪里 —————————— 执行流 一次执行一段 ASP.NET Core 是什么东西…...

学习大数据,所需要Java基础(9)

文章目录 网络编程实现简答客户端和服务器端的交互编写客户端编写服务端 文件上传文件上传客户端以及服务器端实现文件上传服务器端实现&#xff08;多线程&#xff09;文件上传服务器端&#xff08;连接池版本&#xff09;关闭资源工具类 BS架构服务器案例案例分析BS结构服务器…...

Python元组(Tuple)深度解析!

目录 1. 什么是元组&#xff1f; 2. 创建元组 3.访问元组 4.元组的运算 5.修改元组不可行 6.元组的应用场景 前面的博客里&#xff0c;我们详细介绍了列表&#xff08;List&#xff09;这一种数据类型&#xff0c;现在我们来讲讲与列表相似的一种数据类型&#xff0c;元组…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)

目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 ​编辑​编辑 UDP的特征 socke函数 bind函数 recvfrom函数&#xff08;接收函数&#xff09; sendto函数&#xff08;发送函数&#xff09; 五、网络编程之 UDP 用…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究

摘要&#xff1a;在消费市场竞争日益激烈的当下&#xff0c;传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序&#xff0c;探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式&#xff0c;分析沉浸式体验的优势与价值…...

以太网PHY布局布线指南

1. 简介 对于以太网布局布线遵循以下准则很重要&#xff0c;因为这将有助于减少信号发射&#xff0c;最大程度地减少噪声&#xff0c;确保器件作用&#xff0c;最大程度地减少泄漏并提高信号质量。 2. PHY设计准则 2.1 DRC错误检查 首先检查DRC规则是否设置正确&#xff0c;然…...