Python 之 Numpy 框架入门
NumPy
NumPy 是 Python 中用于科学计算的基本包。它是一个 Python 库,提供了一个多维数组对象、各种派生对象(比如屏蔽数组和矩阵) ,以及一系列用于数组快速操作的例程,包括数学、逻辑、形状操作、排序、选择、 i/o、离散傅里叶变换、基本线性代数、基本统计操作、随机模拟等等。
官网文档地址:https://numpy.org/
单纯学习 Numpy 会比较闷,因为 Numpy 是用于科学计算的。只是学习了各种 API 的使用,会很苦闷学来干啥,跟人工智能有什么关系?
安装 numpy 比较简单,直接使用命令安装即可:
pip install numpy
测试是否正常:
import numpy as np
print(np.__version__)

基础使用
基本数据类型
下表列举了常用 NumPy 基本类型。
| 名称 | 描述 |
|---|---|
| bool_ | 布尔型数据类型(True 或者 False) |
| int_ | 默认的整数类型(类似于 C 语言中的 long,int32 或 int64) |
| intc | 与 C 的 int 类型一样,一般是 int32 或 int 64 |
| intp | 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64) |
| int8 | 字节(-128 to 127) |
| int16 | 整数(-32768 to 32767) |
| int32 | 整数(-2147483648 to 2147483647) |
| int64 | 整数(-9223372036854775808 to 9223372036854775807) |
| uint8 | 无符号整数(0 to 255) |
| uint16 | 无符号整数(0 to 65535) |
| uint32 | 无符号整数(0 to 4294967295) |
| uint64 | 无符号整数(0 to 18446744073709551615) |
| float_ | float64 类型的简写 |
| float16 | 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位 |
| float32 | 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位 |
| float64 | 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位 |
| complex_ | complex128 类型的简写,即 128 位复数 |
| complex64 | 复数,表示双 32 位浮点数(实数部分和虚数部分) |
| complex128 | 复数,表示双 64 位浮点数(实数部分和虚数部分) |
每个内建类型都有一个唯一定义它的字符代码,如下:
| 字符 | 对应类型 |
|---|---|
| b | 布尔型 |
| i | (有符号) 整型 |
| u | 无符号整型 integer |
| f | 浮点型 |
| c | 复数浮点型 |
| m | timedelta(时间间隔) |
| M | datetime(日期时间) |
| O | (Python) 对象 |
| S, a | (byte-)字符串 |
| U | Unicode |
| V | 原始数据 (void) |
numpy 有个 dtype 函数,用于定义变量类型,其定义如下:
class numpy.dtype(dtype, align=False, copy=False[, metadata])
比如这段代码定义了一个numpy 中 int32 类型的变量:
import numpy as np
a = np.dtype(dtype="int32")
print(a)
也可以使用短代码:
import numpy as np
a = np.dtype("i")
print(a)
等效代码:
import numpy as np
a = np.dtype(np.int32)
print(a)
运行代码后,都会打印:
int32
这个类型是 numpy 中的类型,不是 Python 中的类型,要注意区分。numpy 的数值类型实际上是 dtype 对象的实例,并对应唯一的字符,包括 np.bool_,np.int32,np.float32,等等。
因为 Python 是弱类型,没有 int32 a = ... 这种语法,所以为了明确定义这个变量是何种类型,需要使用类型的字符串名称。
这句话现在可以先不管,后面会在很多地方使用 dtype,用熟了就知道了。
要注意的是 np.dtype 是创建一个类型标识,本身并没有存储变量值。
示例:
import numpy as np
def test(object, dtype):
if dtype == np.int32:
print(f"{object} int32")
elif dtype == np.int64:
print(f"{object} int64")
elif dtype == np.str_:
print(f"{object} str_")
a = 111
b = np.dtype(dtype="int32")
test(a, b)
c = '111'
d = np.dtype(dtype="str")
test(c, d)
创建基本数组
Numpy 提供了一个多维数组对象、各种派生对象(比如屏蔽数组和矩阵) ,numpy 中最重要的对象是数组和矩阵。所以要学会 numpy ,最基本的是学会 numpy 数组。
numpy 创建数组的定义:
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
参数说明:
| 名称 | 描述 |
|---|---|
| object | 数组或嵌套的数列 |
| dtype | 数组元素的数据类型,可选 |
| copy | 对象是否需要复制,可选 |
| order | 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认) |
| subok | 默认返回一个与基类类型一致的数组 |
| ndmin | 指定生成数组的最小维度 |
创建一个基本数组:
import numpy as np
a = np.array([1, 2, 3])
创建多维数组
import numpy as np
a = np.array([[1, 2], [3, 4]])
print (a)

定义一个数组,然后生成多维数组:
import numpy as np
a = np.array([1, 2, 3, 4, 5], ndmin = 2)
# 相当于 np.array([[1, 2, 3, 4, 5]])
print (a)
b = np.array([1, 2, 3, 4, 5], ndmin = 3)
# 相当于 np.array([[[1, 2, 3, 4, 5]]])
print (b)
c = np.array([[1, 2, 3, 4, 5],[1, 2, 3, 4, 5]], ndmin = 3)
# 相当于 np.array([[[1, 2, 3, 4, 5],[1, 2, 3, 4, 5]]])
print (c)

数组属性
由于 Python 是弱类型,所以想学习和了解细节的时候,会比较懵逼。因此,我们尽量在编写 Python 代码时,获取代码的一些文档注释。
如下面代码中,定义了一个数组:
import numpy as np
a = np.array([[1, 2], [3, 4]])
print (a)
numpy 的数组,其类型为 ndarray[Any, dtype],完整文档如下:
a: ndarray[Any, dtype] = np.array([[1, 2], [3, 4]])
所以,要掌握 numpy 数组,实际上就是在了解 ndarray。
ndarray 中比较重要的属性如下:
| 属性 | 说明 |
|---|---|
| ndarray.ndim | 秩,即轴的数量或维度的数量 |
| ndarray.shape | 数组的维度,对于矩阵,n 行 m 列 |
| ndarray.size | 数组元素的总个数,相当于 .shape 中 n*m 的值 |
| ndarray.dtype | ndarray 对象的元素类型 |
| ndarray.itemsize | ndarray 对象中每个元素的大小,以字节为单位 |
| ndarray.flags | ndarray 对象的内存信息 |
| ndarray.real | ndarray元素的实部 |
| ndarray.imag | ndarray 元素的虚部 |
| ndarray.data | 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。 |
回到之前提到过的 numpy.dtype,结合 numpy.array,其示例代码如下:
import numpy
import numpy as np
a = np.array([1, 2])
print(a.dtype)
print(a)
t = np.dtype(numpy.float64)
b = np.array(object=[1, 2], dtype=t)
print(b.dtype)
print(b)

如果我们不配置 dtype 参数,那么数组的 dtype 会以数组元素类型为依据。如果配置了 dtype,那么数组元素都会被转换为对应的类型,如 np.array(object=[1, 2], dtype='float64') 。
数组生成
zeros、ones、empty 数组生成
numpy.zeros
numpy.zeros 的作用是创建一个元素全部为 0 的数组。
其定义如下:
def zeros(shape, dtype=float, order='C', *, like=None, /)
| 参数 | 描述 |
|---|---|
| shape | 数组形状 |
| dtype | 数据类型,可选 |
| order | 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。 |
创建一个全部由 0 填充的数组:
import numpy as np
# 长度为 2
a = np.zeros(2)
print(a)

np.zeros() 默认创建的数组是 float64 类型,如果需要自定义类型,可以使用 dtype:
import numpy as np
# 长度为 2
a = np.zeros(2,dtype=int)
print(a)

numpy.ones
ones 创建一个元素值均为 1 的数组。
其定义如下:
def ones(shape, dtype=None, order='C', *, like=None)
示例如下:
import numpy as np
# 长度为 2
a = np.ones(2,dtype=int)
print(a)
由于其 API 与 numpy.zeros 一致,因此不再赘述。
numpy.empty
创建一个指定长度的空数组,但是不会对内存区域进行初始化,所以其被分配的内存区域可能已经有值。
其定义如下:
def empty(shape, dtype=None, order='C', *args, **kwargs)
示例:
import numpy as np
# 长度为 2
a = np.empty(2)
print(a)

由于其没有初始化内存,因此内存区域会残留数据。
其它说明
此外,还有三个对应的原型复制函数:
def empty_like(prototype, dtype=None, order=None, subok=None, shape=None
def zeros_like(prototype, dtype=None, order='K', subok=True, shape=None)
def ones_like(prototype, dtype=None, order='K', subok=True, shape=None)
它们的作用是根据数组类型,拷贝一个相同的结构,然后填充对应值。
如下示例,复制数组相同的结构,但是填充的值为 0。
import numpy as np
a = np.array([[1],[1]])
b = np.zeros_like(a)
print(b)

此外,这三个函数,可以传递元组,生成多维的数组(矩阵)。
import numpy
import numpy as np
a = np.zeros(shape=(2, 3, 4), dtype=numpy.double)
print(a)

numpy.random
numpy.random 是一个类,不是一个函数,numpy.random 中有一些随机生成数组的函数。
以下是一些常用的 API:
#生成具有给定形状的均匀分布的随机样本,范围在[0, 1)之间。
numpy.random.rand(size)
# 生成具有给定形状的标准正态分布(平均值为0,方差为1)的随机样本。随机样本取值范围是[0,1)。
numpy.random.randn(size)
# 正态分布,指定均值和方差
numpy.random.normal(loc=0.0, scale=1.0, size=None)
# 随机生成
numpy.random.random(size=None)
# 从给定的上下限范围内生成随机整数。
numpy.random.randint(low, high=None, size=None, dtype=int)
# 从给定的一维数组中生成随机样本。
numpy.random.choice(a, size=None, replace=True, p=None)
# 随机打乱给定数组的顺序。
numpy.random.shuffle(x)
随机数值生成和正态分布生成示例如下:
import numpy as np
a = np.random.rand(10)
b = np.random.rand(10)
print(a)
print(b)
[0.39809428 0.83922059 0.10808865 0.00332159 0.75922001 0.26850704
0.04497839 0.59012908 0.0438718 0.59988563]
[0.78161896 0.91401858 0.10980276 0.89723959 0.06802148 0.18993732
0.10664519 0.14121531 0.27353601 0.56878734]

x1 = np.random.randint(10, size=6) # 一维数组
x2 = np.random.randint(10, size=(3, 4)) # 二维数组
x3 = np.random.randint(10, size=(3, 4, 5)) # 三维数组
对于其它 API,由于篇幅有限,不再赘述。
numpy.arange
numpy.arange 用于有规律地生成数组。
其定义如下:
numpy.arange([start, ]stop, [step, ]dtype=None, *, like=None)
| 参数 | 描述 |
|---|---|
start |
起始值,默认为0 |
stop |
终止值(不包含) |
step |
步长,默认为1 |
dtype |
返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。 |
numpy.arange 默认从 0 开始生成数组,间隔为 1。
比如,下面代码会生成一个元素值不超过 4 的数组,即范围是 [0,4) 。
import numpy as np
# 长度为 4
a = np.arange(4)
print(a)

arange(start, stop) 指定开始结束范围,但是依然步长为 1。
import numpy as np
# 长度为 4
a = np.arange(1,4)
print(a)

arange(start, stop, step) 自定义设置范围和步长。
import numpy as np
# 长度为 4
a = np.arange(1,10,3)
print(a)
numpy.linspace
numpy.linspace 可以使用线性间隔的方式生成数组:
np.linspace(0, 10, num=5)

num=5 的含义是从来的之间平均取得 5 个数值。
[ 0.
2.5
5.
7.5
10. ]

但是跟我们预料的结果可能不太一样,因为 linspace() 是包括起始点的,所以 0-10 其实个数是 11 个。
import numpy as np
# 长度为 4
a = np.linspace(0, 10, num=10)
print(a)

import numpy as np
# 长度为 4
a = np.linspace(0, 10, num=11)
print(a)

数组操作
数组排序
排序会返回数组的副本。
主要排序函数如下:
sort :按照大小排序
argsort:它是沿指定轴的间接排序,
lexsort:它是对多个键的间接稳定排序,
searchsorted, 它将查找排序数组中的元素。
partition, 分区,这是一个部分排序。
对于 numpy 的数组,请使用 numpy 的函数排序,不要使用 Python 自带的函数排序。
import numpy as np
# 长度为 4
a = np.random.rand(10)
print(a)
# 使用 Python 内置函数
print(sorted(a))
# 使用 numpy.sort
print(np.sort(a))

如上图所示,使用 Python 自带的函数,会导致精确度出现问题。
切片索引
可以使用 slice(start,stop,step) 函数或 [start:stop:step] 进行切片。
import numpy as np
a = np.arange(10)
print(a)
# 索引范围是 2-7 ,间隔为2
# [0 1 2 3 4 5 6 7 8 9]
s1 = slice(2, 7, 2)
# 索引范围是 2-8 ,间隔为2
# [0 1 2 3 4 5 6 7 8 9]
s2 = slice(2, 8, 2)
print(a[s1])
print(a[s2])

等同于:
import numpy as np
a = np.arange(10)
print(a)
print(a[2:7:2])
print(a[2:8:2])
对于二维数组,可以通过坐标点取值。
import numpy as np
x = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[9, 10, 11]])
# 左上角、右上角、左下角、右下角 四个点
a1 = np.array([[0, 0], [3, 3]])
a2 = np.array([[0, 2], [0, 2]])
y = x[a1, a2]
print(y)
[[ 0 2]
[ 9 11]]
取值时,跟一维数组一致,可以通过索引取值。
import numpy as np
x = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[9, 10, 11]])
y = x[1:2]
print(y)

数组还可以通过表达式取值,如 x>5、x<5 等。
import numpy as np
x = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
print(x)
print(x[x > 5])
详细的表达式操作方法,可以查阅官网文档,这里不再赘述。
数组运算符
numpy 数组,可以通过操作符直接操作。
如两个数组的值相加:
import numpy as np
a1 = np.array([1, 2, 3])
a2 = np.array([4, 5, 6])
a3 = a1 + a2
a4 = a1 * a2
print(a3)
print(a4)
得到:
[5 7 9]
[ 4 10 18]
广播规则
对于不同形状的数组(即维数不同),numpy 可以自动补全维数。
其规则约束如下:
两个数组的形状相同
维数比较少的数组,需要是一维数组。
import numpy as np
a = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
b = np.array([100, 100, 100])
print(a + b)

[ [
[1, 2, 3] + [100, 100, 100]
[4, 5, 6] + [100, 100, 100]
[7, 8, 9] + [100, 100, 100]
] ]
相加后:
[
[101 102 103]
[104 105 106]
[107 108 109]
]
但是要注意,如果两个数组的一个维中,元素个数不一致,则运算会报错。
import numpy as np
a1 = np.array([1, 2, 3])
a2 = np.array([4, 5, 6, 7])
a3 = a1 + a2
print(a3)

如果两个数组维度一致,但是形状不一样,维数少的数组必须是一维数组。
如下面代码会报错:
import numpy as np
a = np.array([[1, 2, 3],
[1, 1, 1],
[1, 1, 1]])
b = np.array([[1, 1, 1],
[2, 2, 2]])
print(a + b)

修改数组
Numpy 中包含了一些函数用于处理数组,大概可分为以下几类:
- 修改数组形状
- 翻转数组
- 修改数组维度
- 连接数组
- 分割数组
- 数组元素的添加与删除
修改数组的形状
主要有以下函数:
| 函数 | 描述 |
|---|---|
reshape |
不改变数据的条件下修改形状 |
flat |
数组元素迭代器 |
flatten |
返回一份数组拷贝,对拷贝所做的修改不会影响原始数组 |
ravel |
返回展开数组 |
将一维数组,转换为二维数组,每个数组元素有 3 个,其示例如下:
import numpy as np
a = np.arange(6).reshape(2, 3)
b = np.array([0,1,2,3,4,5]).reshape(2, 3)
print(a)
print(b)
[[0 1 2]
[3 4 5]]
[[0 1 2]
其它几个函数可以使用以下示例表达:
import numpy as np
a = np.arange(10)
print(a)
# 数组迭代器 .flat
for element in a.flat:
print(element)
# 将数组转换为二维数组
b = a.reshape(2,5)
print("将数组转换为二维:")
print(b)
print("将多维数组合并为一维:")
c = b.ravel()
print(c)
[0 1 2 3 4 5 6 7 8 9]
0
1
2
3
4
5
6
7
8
9
将数组转换为二维:
[[0 1 2 3 4]
[5 6 7 8 9]]
将多维数组合并为一维:
[0 1 2 3 4 5 6 7 8 9]
翻转数组
其常用函数定义如下:
| 函数 | 描述 |
|---|---|
transpose |
对换数组的维度 |
ndarray.T |
和 self.transpose() 相同 |
rollaxis |
向后滚动指定的轴 |
swapaxes |
对换数组的两个轴 |
transpose 、ndarray.T 都可以将数组翻转,例如将 2x5 的数组翻转为 5x2。
import numpy
import numpy as np
a = np.arange(10).reshape(2,5)
print(a)
b = numpy.transpose(a)
c = a.T
print(b)
print(c)
[[0 1 2 3 4]
[5 6 7 8 9]]
[[0 5]
[1 6]
[2 7]
[3 8]
[4 9]]
[[0 5]
[1 6]
[2 7]
[3 8]
[4 9]]
rollaxis 、swapaxes 都有三个参数:
arr:数组
axis:要向后滚动的轴,其它轴的相对位置不会改变。取值范围为 [0, a.ndim]
start:默认为零,表示完整的滚动。会滚动到特定位置。取值范围为 [-a.ndim, a.ndim]
注意:二维只有 0、1 两个轴,三维有 0、1、2 三个轴。axis、start 都是填写轴的序号。

使用 print(a1.ndim) 可以打印数组的维数,即轴数。
swapaxes 用于指定交互两个轴的位置。
如:
import numpy
import numpy as np
a1 = np.array([
[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]
])
b = np.swapaxes(a1, 0, 1)
print(b)
原数组:
[[0, 0, 0, 0]
[1, 1, 1, 1]
[2, 2, 2, 2]
[3, 3, 3, 3]]
变换后的数组:
[[0 1 2 3]
[0 1 2 3]
[0 1 2 3]
[0 1 2 3]]
也可以理解成坐标系的 x 轴 和 y 轴,x 轴变成了 y 轴。
swapaxes 在更多维数组的情况下,有更多的轴,例如三维的 x、y、z 三个轴。这里不再赘述。
至于 numpy.rollaxis ,我也不会。
修改数组维度
其主要函数如下:
| 维度 | 描述 |
|---|---|
broadcast |
产生模仿广播的对象 |
broadcast_to |
将数组广播到新形状 |
expand_dims |
扩展数组的形状 |
squeeze |
从数组的形状中删除一维条目 |
连接数组
其主要函数如下:
| 函数 | 描述 |
|---|---|
concatenate |
连接沿现有轴的数组序列 |
stack |
沿着新的轴加入一系列数组。 |
hstack |
水平堆叠序列中的数组(列方向) |
vstack |
竖直堆叠序列中的数组(行方向) |
numpy.concatenate 将两个数组拼接成一个新的数组:
import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])
c = np.concatenate((a, b))
print(c)

分割数组
其主要函数如下:
| 函数 | 数组及操作 |
|---|---|
split |
将一个数组分割为多个子数组 |
hsplit |
将一个数组水平分割为多个子数组(按列) |
vsplit |
将一个数组垂直分割为多个子数组(按行) |
其使用方法比较简单,这里不再赘述。
增删数组元素
其主要函数如下:
| 函数 | 元素及描述 |
|---|---|
resize |
返回指定形状的新数组 |
append |
将值添加到数组末尾 |
insert |
沿指定轴将值插入到指定下标之前 |
delete |
删掉某个轴的子数组,并返回删除后的新数组 |
unique |
查找数组内的唯一元素 |
其使用方法比较简单,这里不再赘述。
数组迭代
前面提到过 .flat 。
import numpy as np
# 这里是二维
a = np.arange(10).reshape(2,5)
# 数组迭代器 .flat
for element in a.flat:
print(element)
.flat 会按照顺序打印每一个元素。
0
1
2
3
4
5
6
7
8
9
.nditer 也是如此。
import numpy as np
a = np.arange(10).reshape(2,5)
# 数组迭代器 .flat
for element in np.nditer(a):
print(element)
.nditer 可以控制遍历规则。
for x in np.nditer(a.T, order='C'),默认,行遍历。
for x in np.nditer(a, order='F'),列遍历。
import numpy as np
a = np.arange(10).reshape(2, 5)
# 数组迭代器 .flat
for element in np.nditer(a, order='F'):
print(element)
0
5
1
6
2
7
3
8
4
9
.nditer 可以控制迭代多维数组的维还是元素。
前面提到的代码,均是迭代逐个元素。
如果设置了 flags 参数,则可以迭代维。
import numpy as np
a = np.arange(10).reshape(2, 5)
# 数组迭代器 .flat
for element in np.nditer(a, order='F', flags=['external_loop']):
print(element)
原数组:
[[0 1 2 3 4]
[5 6 7 8 9]]
按照迭代方向 F:
[0 5]
[1 6]
[2 7]
[3 8]
[4 9]
Python 之 Numpy 框架入门的更多相关文章
- Python Flask Web 框架入门
Python Flask 目录 本文主要借鉴 letiantian 的文章 http://www.letiantian.me/learn-flask/ 一.简介 二.安装 三.初始化Flask 四.获 ...
- [Python] Scrapy爬虫框架入门
说明: 本文主要学习Scrapy框架入门,介绍如何使用Scrapy框架爬取页面信息. 项目案例:爬取腾讯招聘页面 https://hr.tencent.com/position.php?&st ...
- 比我的脸还干的gan货——Python Flask Web 框架入门
Flask是一个轻量级的基于Python的web框架. 本文适合有一定HTML.Python.网络基础的同学阅读. 1. 简介 这份文档中的代码使用 Python 3 运行.是的,所以读者需要自己在电 ...
- Python爬虫Scrapy框架入门(0)
想学习爬虫,又想了解python语言,有个python高手推荐我看看scrapy. scrapy是一个python爬虫框架,据说很灵活,网上介绍该框架的信息很多,此处不再赘述.专心记录我自己遇到的问题 ...
- Python selenium自动化测试框架入门实战--登录测试案例
本文为Python自动化测试框架基础入门篇,主要帮助会写基本selenium测试代码又没有规划的同仁.本文应用到POM模型.selenium.unittest框架.configparser配置文件.s ...
- Python爬虫Scrapy框架入门(1)
也许是很少接触python的原因,我觉得是Scrapy框架和以往Java框架很不一样:它真的是个框架. 从表层来看,与Java框架引入jar包.配置xml或.property文件不同,Scrapy的模 ...
- Python的Flask框架入门-Ubuntu
全文请见tuts code:An Introduction to Python's Flask Framework Flask是Python一个小而强大的web框架.学起来简单,用起来也容易,能够帮你 ...
- Python爬虫Scrapy框架入门(2)
本文是跟着大神博客,尝试从网站上爬一堆东西,一堆你懂得的东西 附上原创链接: http://www.cnblogs.com/qiyeboy/p/5428240.html 基本思路是,查看网页元素,填写 ...
- Python爬虫Scrapy框架入门(3)
往往需要爬取的网页是呈一个树状结构.比如,需要先爬取一个目录,然后再在目录中选择具体的爬取目标.而目录和具体目标之间,网页结构不同,使得我们不能使用相同的爬取策略. 从之前的经验来看,我们对scrap ...
- Python云端系统开发入门——框架基础
Django框架基础 这是我学习北京理工大学嵩天老师的<Python云端系统开发入门>课程的笔记,在此我特别感谢老师的精彩讲解和对我的引导. 1.Django简介与安装 Django是一个 ...
随机推荐
- 【教程】AWD中如何通过Python批量快速管理服务器?
前言 很多同学都知道,我们常见的CTF赛事除了解题赛之外,还有一种赛制叫AWD赛制.在这种赛制下,我们战队会拿到一个或多个服务器.服务器的连接方式通常是SSH链接,并且可能一个战队可能会同时有多个服务 ...
- [golang]使用logrus自定义日志模块
简介 logrus是一个第三方日志库,性能虽不如zap和zerolog,但方便易用灵活.logrus完全兼容标准的log库,还支持文本.JSON两种日志输出格式. 特点 相较于标准库,logrus有更 ...
- 详细讲解原生js拖拽
场景描述 今天遇见一个问题,那就是产品希望在弹出来的窗口. 可以移动这个弹窗的位置 增加用户体验,我们直接使用的element-ui中的 Dialog 对话框 我们现在需要拖拽标题,移动元素位置 元素 ...
- 《Kali渗透基础》06. 主动信息收集(三)
@ 目录 1:服务识别 1.1:NetCat 1.2:Socket 1.3:dmitry 1.4:nmap 2:操作系统识别 2.1:Scapy 2.2:nmap 2.3:p0f 3:SNMP 扫描 ...
- 代码随想录算法训练营第二十五天| 216.组合总和III 17.电话号码的字母组合
216.组合总和III 卡哥建议:如果把 组合问题理解了,本题就容易一些了. 题目链接/文章讲解:https://programmercarl.com/0216.%E7%BB%84%E5%90%8 ...
- SpringBoot获取树状结构数据-SQL处理
前言 在开发中,层级数据(树状结构)的获取往往可能是我们一大难点,我现在将自己获取的树状结构数据方法总结如下,希望能给有需要的小伙伴有所帮助! 一.测试数据准备 /* Navicat Premium ...
- Jenkins持续集成入门到精通(入门篇)
1. 什么是持续集成 持续集成(Continuous integration,简称CI)指的是频繁将代码集成到主干.它的目的,就是让产品可以快速迭代,同时保持高质量.核心措施,代码集成到主干之前,必须 ...
- Record -「NOIP-S 2020」赛后总结
不是特别想说伤心的事情. T1 一遍过完所有大样例,此时只过去了十几二十分钟,不过之前花了半个小时通读了整个 PDF 所以此时大概过了 1h. T2 大概花了十几分钟胡出了一个反着枚举就是正解的 n^ ...
- docker bridge网络类型研究
bridge模式是docker的默认网络模式,使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能.可以使用iptables -t nat -vnL ...
- getchar()和putchar()
#include <stdio.h> #include <stdlib.h> int main() { char ch; /*.putchar() a. putchar函数的格 ...
