Python第三方库numpy的简单入门使用

首先,我们需要导入包文件

1
import numpy as np

一、numpy中的一般语法

1
2
3
4
5
6
7
8
9
10
11
12
# 矩阵的逆、转置及秩
data_1 = np.matrix('3 4 5;7 8 9')
print(data_1)
print("矩阵的逆:")
data_2 = data_1.I
print(data_2)
print("矩阵的转置:")
data_3 = data_1.T
print(data_3)
print("矩阵的秩:")
data_4 = np.linalg.matrix_rank(data_1)
print(data_4)
[[3 4 5]
 [7 8 9]]
矩阵的逆:
[[-1.08333333  0.58333333]
 [-0.08333333  0.08333333]
 [ 0.91666667 -0.41666667]]
矩阵的转置:
[[3 7]
 [4 8]
 [5 9]]
矩阵的秩:
2
1
2
# 矩阵的维度(也称为轴数)
print(data_1.ndim)
2

二、数组的创建

  1. 创建二维数组
    这里强调:使用matrix只能创建二维矩阵,而是用非matrix方法可以创建高维矩阵
1
2
3
4
5
6
# 全0的矩阵
arr_1 = np.matrix(np.zeros((3, 3)))
print(arr_1)
# 或者
arr_1 = np.zeros((3, 3))
print(arr_1)
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
1
2
3
4
5
6
# 全1的矩阵
arr_2 = np.matrix(np.ones((3, 3)))
print(arr_2)
# 或者
arr_2 = np.ones((3, 3))
print(arr_2)
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
1
2
3
# 创建随机矩阵
arr_3 = np.matrix(np.random.rand(3, 4))
arr_3
matrix([[0.48890396, 0.09218043, 0.38339213, 0.61843015],
        [0.35092127, 0.08485116, 0.84651857, 0.4481831 ],
        [0.88727766, 0.56471182, 0.49473952, 0.69027512]])
1
2
3
# 创建整数随机矩阵
arr_4 = np.matrix(np.random.randint(5, 10, size=(3, 4)))
arr_4
matrix([[7, 7, 7, 5],
        [6, 5, 8, 5],
        [5, 6, 7, 6]])
1
2
3
4
# 创建对角矩阵
new_list = [i for i in range(3, 7)]
arr_5 = np.matrix(np.diag(new_list))
arr_5
matrix([[3, 0, 0, 0],
        [0, 4, 0, 0],
        [0, 0, 5, 0],
        [0, 0, 0, 6]])
1
2
3
# 创建单位矩阵
arr_6 = np.eye(3)
arr_6
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
1
2
3
4
# 改变矩阵的形状
print(arr_4)
arr_7 = arr_4.reshape(4, 3)
arr_7
[[7 7 7 5]
 [6 5 8 5]
 [5 6 7 6]]





matrix([[7, 7, 7],
        [5, 6, 5],
        [8, 5, 5],
        [6, 7, 6]])
  1. 高维数组
1
2
3
4
# 例如创建3维的数组
arr_8 = np.arange(24).reshape(2, 3, 4)
print(arr_8)
print("数组维度:"+str(arr_8.ndim))
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
数组维度:3

三、numpy的索引和切片

1
2
3
print(arr_8)
print("单独获取到一个值")
print(arr_8[0,0,3])
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
单独获取到一个值
3
1
2
3
print(arr_8)
print("获取到深度为0的所有值")
print(arr_8[0,:,:])
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
获取到深度为0的所有值
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
1
2
3
print(arr_8)
print("获取到深度为0的前两行的值")
print(arr_8[0,:2,:])
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
获取到深度为0的前两行的值
[[0 1 2 3]
 [4 5 6 7]]
1
2
3
print(arr_8)
print("获取到深度为0的前两行后两列的值")
print(arr_8[0,:2,-2:])
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
获取到深度为0的前两行后两列的值
[[2 3]
 [6 7]]
1
2
3
4
5
6
7
8
print(arr_8)
print("获取到深度为0的前两行后两列的值并替换为-2")
print("获取到深度为0的前两行后两列的值")
print(arr_8[0,:2,-2:])
print("替换为-2")
arr_8[0,:2,-2:] = -2
print("原来数组")
print(arr_8)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
获取到深度为0的前两行后两列的值并替换为-2
获取到深度为0的前两行后两列的值
[[2 3]
 [6 7]]
替换为-2
原来数组
[[[ 0  1 -2 -2]
  [ 4  5 -2 -2]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

四、numpy的合并功能

1. 在第一轴合并
2. 在第二轴合并
3. 在第三轴合并
4. 在任意轴合并
1
2
3
4
5
6
7
# 1. 在第一轴合并
# vstack
print("合并前的arr_8\n"+str(arr_8))
temp_1 = arr_8
temp_2 = arr_8
temp = np.vstack((temp_1, temp_2))
print("两个arr_8合并后\n"+str(temp))
合并前的arr_8
[[[ 0  1 -2 -2]
  [ 4  5 -2 -2]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
两个arr_8合并后
[[[ 0  1 -2 -2]
  [ 4  5 -2 -2]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]

 [[ 0  1 -2 -2]
  [ 4  5 -2 -2]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
1
2
3
4
5
6
7
# 2. 在第二轴合并
# hstack
print("合并前的arr_8\n"+str(arr_8))
temp_1 = arr_8
temp_2 = arr_8
temp = np.hstack((temp_1, temp_2))
print("两个arr_8合并后\n"+str(temp))
合并前的arr_8
[[[ 0  1 -2 -2]
  [ 4  5 -2 -2]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
两个arr_8合并后
[[[ 0  1 -2 -2]
  [ 4  5 -2 -2]
  [ 8  9 10 11]
  [ 0  1 -2 -2]
  [ 4  5 -2 -2]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]
  [12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
1
2
3
4
5
6
7
# 3. 在第三轴合并
# dstack
print("合并前的arr_8\n"+str(arr_8))
temp_1 = arr_8
temp_2 = arr_8
temp = np.dstack((temp_1, temp_2))
print("两个arr_8合并后\n"+str(temp))
合并前的arr_8
[[[ 0  1 -2 -2]
  [ 4  5 -2 -2]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
两个arr_8合并后
[[[ 0  1 -2 -2  0  1 -2 -2]
  [ 4  5 -2 -2  4  5 -2 -2]
  [ 8  9 10 11  8  9 10 11]]

 [[12 13 14 15 12 13 14 15]
  [16 17 18 19 16 17 18 19]
  [20 21 22 23 20 21 22 23]]]
1
2
3
4
5
6
7
8
# 4. 任意轴合并
# concatenate
print("合并前的arr_8\n"+str(arr_8))
temp_1 = arr_8
temp_2 = arr_8
# axis表示设置在何处轴合并,默认在第一轴
temp = np.concatenate((arr_8, arr_8), axis=2)
print("两个arr_8合并后\n"+str(temp))
合并前的arr_8
[[[ 0  1 -2 -2]
  [ 4  5 -2 -2]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
两个arr_8合并后
[[[ 0  1 -2 -2  0  1 -2 -2]
  [ 4  5 -2 -2  4  5 -2 -2]
  [ 8  9 10 11  8  9 10 11]]

 [[12 13 14 15 12 13 14 15]
  [16 17 18 19 16 17 18 19]
  [20 21 22 23 20 21 22 23]]]

Python迭代器及生成器的简单理解

迭代器

  在使用列表时,直接将数据存入列表将会占据大量空间,且复用率较低,
为解决这个问题,这里了解一下迭代器,从而创建一种数据产生的方式,以此来节省空间。

迭代对象

  注意,这里需要使用到内建函数iter,简单理解为,使用了iter才会是一个可迭代对象,关于这部分,我们可以对一些对象做一些判断,从而清楚是不是可迭代对象,比如L1列表:

1
2
3
4
from collections.abc import Iterable
# 判断L1是否为可迭代对象
L1 = [i for i in range(4)]
print(isinstance(L1, Iterable)) # 结果为True,确定为迭代对象

  这里我们使用iter()方法和next()方法来将元素取出。

1
2
3
4
5
L2 = L1.__iter__()
# L2 = iter(L1) # 和上面一句等价
print(next(L2))
print(L2.__next__()) # 和上面一句等价
print(next(L2))

  在这里我们实现了使用for循环来取出元素的方法,在了解这里之后,我们开始做一个自己的迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 构造迭代器
class NewIter():
# 用于生成斐波那契数列
def __init__(self, num):
self.num = num
self.a = 0
self.b = 1

def __iter__(self):
# 创建可迭代对象
return self

def __next__(self):
while self.num > 0:
result = self.a
self.a, self.b = self.b, self.a + self.b
self.num -= 1
return result
# 循环结束后跳出
raise StopIteration

new_iter = NewIter(5)
print(next(new_iter))
print(next(new_iter))

生成器

  这里引入生成器个概念,生成器能做到迭代器能做的所有事,由于自动创建了iter()和next()方法,生成器显得特别简洁。除了创建和保存程序状态的自动方法,当
发生器终结时,还会自动抛出 StopIteration 异常。简单理解他就是迭代器的一种!!使用yield即可实现。

1
2
3
4
5
6
7
8
9
10
11
12
# 生成器实现
def new_create(num):
# 用于生成斐波那契数列
a, b = 0, 1
while num > 0:
yield a
a, b = b, a+b
num -= 1

new_iter = new_create(5)
print(next(new_iter))
print(next(new_iter))

结语

  目的就是节省空间,提高复用率

Python装饰器的简单理解

装饰器

  通俗点理解就是锦上添花,关于这块需要参考一些软件开发的设计模式,在这里引入一个小的故事。
  公司招了一个人A,某一天,项目组想要给一个接口添加一些时间计算,具体时间计算没有说,但是这个功能要加,A呢就去查看接口中的代码,在代码中添加了一个时间计算,过了两天,项目组要求所有接口全部添加时间计算,此时A则一个个的去每个接口中添加时间计算,以至于天天晚上加班,结果没过多久就被炒鱿鱼了。此时来了B,他先写了个时间计算函数并在每个接口头部添加这个函数名,实现了对应的加时间计算功能。没多久就升职加薪了。
  看到这里,不禁会想,为什么呢???其实这里涉及到一个软件开发的设计模式-开闭原则(简单说就是功能可以加,代码修改是不允许的),A就明显犯了这个错误,
而B则是使用到了我们接下来要说到的装饰器。

引入

  在了解装饰器之前,请先了解闭包的相关概念!!以及高阶函数的概念!!
这里我们有一个阶乘功能的函数

1
2
3
4
5
6
7
def product(value):
# 实现阶乘功能
result = 1
while value > 0:
result *= value
value -= 1
print(result)
  1. 我们需要添加一个计算运行时间的功能,请记住,不要改动product函数,直接做功能添加,这里使用装饰器处理。首先我们创建一个装饰器:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import time

    def count_time(func):
    def call_func(var):
    t1 = time.time()
    func(var)
    t2 = time.time()
    print('消耗时间为:'+ str(t2-t1))
    return call_func
  2. 对原有函数进行装饰改造
    1
    2
    3
    4
    5
    6
    7
    8
    @count_time
    def product(value):
    # 实现阶乘功能
    result = 1
    while value > 0:
    result *= value
    value -= 1
    print(result)
  3. 细节理解
      在第二步中的@count_time其实就是装饰器的基本使用,我们在使用product(100)时,解释器不会直接去调用product函数,而是实现调用count_time功能,并将返回的call_func返回给product,也就是说此时的product其实是指向call_func的,当执行product(100)时,其实是在向call_func传递参数,实现功能,简单理解可以使用以下两行代码来表示:
    1
    2
    product = count_time(product) # 此时的product是指向call_func函数的
    product(100) # 相当于执行call_func(100)

    更高一级的操作

  4. 原函数需要传递多个参数
      这里很好处理,很正常函数传递参数相同,我们在装饰器中最内层函数中需要传递的变量名改为*args, **kwargs,在执行时,将其直接传入即可。
  5. 原函数有返回值
      这里我们可以直接使用return将装饰器中最内层的执行函数部分return出去即可,比如:
    1
    2
    3
    4
    def count_time(func):
    def call_func(var):
    return func(var)
    return call_func
  6. 两个装饰器同时装饰同一个函数
      先看一下伪代码
    1
    2
    3
    4
    @装饰器1
    @装饰器2
    def fun():
    pass
      意思很简单,就是在原来函数基础上加两个新功能,但是关于执行顺序是怎么样的呢?
      就不买关子了,装饰器1先执行,但装饰器1最后装饰,其实这里和堆栈很相似,若是方便,可以自己编代码,打断点调试一下就知道了。

    结语

    未完待续…

闭包的简要介绍

闭包

  • 是内层函数对外层函数非全局变量的应用
  • 闭包会一直存在计算机内存中,不会因为函数执行的结束而释放

举例说明

  这里我们做一个求和函数,但是我们需要做到每次求和后也返回一个平均值及对应个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def make_averager():
count = 0
total = 0

def fun(var):
# nonlocal count, total # 这里不加会报错
count += 1
total += var
print(total)
print(str(total/count) + ' , ' + str(count))
return fun


if __name__ == "__main__":
# 这里用到了高阶函数的定义,简单说就是可以将函数的返回值存储在变量中使用
average = make_averager()
average(5)
average(6)
average(7)

  很糟糕,这里会有一个报错UnboundLocalError: local variable ‘count’ referenced before assignment,关于这里其实和变量的使用范围有关,在fun函数内部使用关键字nonlocal添加nonlocal count, total即可解决。
  nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量。
  简单来说就是在修改函数外部的变量,需要使用global;但是在闭包中,修改外层函数中的变量则需要时使用到nonlocal。

Python连接C实现高效编程demo

一、前言

作为一门经典的编程语言,这些年来,C有着重要的地位,在各个领域的使用都是相当重要的地位!而Python作为较新式的语言,相对而言入门更加简单,适合新手来学习!但是作为一门动态的脚本语言,其效率相对C来说还是有些捉急的。在这里,我们引入一个demo来作为Python和C混合编程的一个基础。

二、编写代码

在这里我会使用对比的方式来比较两种语言计算一个较大数字求和时的耗时情况,从而直观体验其中的差别。同时这里会引入混合编程的概念。

  1. 编写C的代码

    1
    2
    3
    4
    5
    6
    7
    8
    #include<stdio.h>

    void add(long VALUE){
    long sum = 0;
    for (long i = 1;i < VALUE; i ++)
    sum += i;
    printf("C求和结果为: %ld\n", sum);
    }
  2. 编写Python代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import time

    VALUE = 9999999

    t1 = time.time()
    sum = 0
    for i in range(1, VALUE):
    sum += i
    print('for循环求和结果为:'+ str(sum))
    t2 = time.time()
    print('for循环求和开销时间为:'+ str(t2-t1))
  3. 将之前的C代码编译成Python可以读取调用的文件

    • gcc -fPIC -shared C的代码 -o 后续调用文件名.so
      例如: gcc -fPIC -shared sum.c -o csum.so
  4. 将csum.so加载到Python中,进行编写

    • 导入库文件from ctypes import cdll
    • 调用文件
      1
      2
      result = cdll.LoadLibrary("./csum.so")
      result.add(VALUE)
  5. 最终Python代码sum.py是酱紫

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import time
    from ctypes import cdll

    VALUE = 9999999

    # 使用Python求和
    t1 = time.time()
    sum = 0
    for i in range(1, VALUE):
    sum += i
    print('for循环求和结果为:'+ str(sum))
    t2 = time.time()
    print('for循环求和开销时间为:'+ str(t2-t1))
    print('-'*30)

    # Python连接C求和
    t1 = time.time()
    result = cdll.LoadLibrary("./csum.so")
    result.add(VALUE)
    t2 = time.time()
    print('使用C求和开销时间为:'+ str(t2-t1))
  6. 最终结果

    1
    2
    3
    4
    5
    for循环求和结果为:49999985000001
    for循环求和开销时间为:3.156290292739868
    ------------------------------
    C求和结果为: 49999985000001
    使用C求和开销时间为:0.043367624282836914

    三、结语

    由上述可以看出来,同样使用for循环,但是使用c的效率是非常非常高的,所以针对一些特殊场景,使用c编写,然后用Python调用也是不错的方法。

使用高德地图API创建一个属于自己的天气闹钟

前言

本着是使用树莓派做一个个人天气预报的,通过百度也看到很多大神使用各种各样的方法来实现,本着简单、免费的想法,我去弄了个高德的开发者账号(ps:其实就是懒,哈哈哈哈哈),这个账号认证后每天有 300000次,其实也够我们自己去使用了,哈哈哈哈!后面关于文本合成语音的部分,打算接入阿里、讯飞的api的,emmm有点贵,算了,使用第三方库讲究着用吧(ps:声音确实是好僵硬)!

准备

  1. 在这里,我们需要提前安装好requests库、pyttsx3库。
    pip3 install requests
    pip3 install pyttsx3
  2. 进入高德开发者平台,注册账号,按照流程创建一个应用(是web服务的api),此时就可以获取到一个key值,这个值在后面会用到,记得保存一下。
  3. 打开高德的api使用文档,好了,开始撸代码…

    开始撸代码

    这里我们有三个任务
  • 获取当前地理位置
  • 根据当前的地理位置来获取天气情况
  • 将得到的文本数据使用语音合成出来
  1. 首先我们来看如何获取地理位置信息
  • 这里我们可以使用web服务的api中的IP查询来获取到对应的城市名和城市的adcode编码

  • 这里我们可以看下这张表

    参数名

    含义

    规则说明

    是否必须

    缺省值

    key

    请求服务权限标识

    用户在高德地图官网申请Web服务API类型KEY

    必填

    ip

    ip地址

    需要搜索的IP地址(仅支持国内)

    若用户不填写IP,则取客户http之中的请求来进行定位

    可选

    sig

    签名

    选择数字签名认证的付费用户必填

    可选

    output

    返回格式

    可选值:JSON,XML

    可选

    JSON


    名称

    含义

    规则说明

    status

    返回结果状态值

    值为0或1,0表示失败;1表示成功

    info

    返回状态说明

    返回状态说明,status为0时,info返回错误原因,否则返回“OK”。

    infocode

    状态码

    返回状态说明,10000代表正确,详情参阅info状态表

    province

    省份名称

    若为直辖市则显示直辖市名称;

    如果在局域网 IP网段内,则返回“局域网”;

    非法IP以及国外IP则返回空

    city

    城市名称

    若为直辖市则显示直辖市名称;

    如果为局域网网段内IP或者非法IP或国外IP,则返回空

    adcode

    城市的adcode编码


    rectangle

    所在城市矩形区域范围

    所在城市范围的左下右上对标对

    我们可以在使用时直接请求,此时可以获取到城市的adcode,那么我们直接调用返回结果即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def get_citycode():
    # 获取当前位置编码
    url = 'https://restapi.amap.com/v3/ip?'
    word = None
    try:
    r = requests.get(url, params=set_params(word))
    text = r.json()
    adcode = text['adcode']
    finally:
    return adcode
  1. 获取地区天气情况
  • 这里我们可以使用web服务的api中的天气查询来获取到对应的城市的天气,在api使用说明中明确表示,需要传入的参数至少有adcode哦!!好在我们之前已经获取到了。
  • 开始请求数据,并处理返回的数据,这里我就取几项数据,具体可以自定义。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    def get_weather():
    # 获取当前位置天气
    url = 'https://restapi.amap.com/v3/weather/weatherInfo?'
    word = get_citycode()
    weather_dict = {}
    try:
    r = requests.get(url, params=set_params(word))
    text = r.json()
    if text['info'] == 'OK':
    weather_dict['-'] = text['lives'][0]['city']
    weather_dict['天气'] = text['lives'][0]['weather']
    weather_dict['温度'] = text['lives'][0]['temperature']
    weather_dict['空气湿度'] = text['lives'][0]['humidity']
    weather_dict['风向'] = text['lives'][0]['winddirection']
    weather_dict['风力级别'] = text['lives'][0]['windpower']
    finally:
    return weather_dict
  1. 开始语音合成处理
    在这一步,需要使用到pyttsx3,查阅技术文档后,直接使用即可(ps:反正语音不是很好听,也就不做过多解释了,直接上代码)
    1
    2
    3
    4
    5
    6
    7
    8
    def read_data():
    # 阅读获取的文本
    weather = get_weather()
    engine = pyttsx3.init()
    rate = engine.getProperty('rate')
    engine.setProperty('rate', rate-10)
    engine.say(weather)
    engine.runAndWait()
  2. 补充,关于代码中set_params函数部分,可以这样写就行
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def set_params(word):
    # 设置请求表单
    if word == None:
    params = {
    'key':你自己的key,
    }
    else:
    params = {
    'key':你自己的key,
    'city':word,
    # base是获取当前天气,而all可以返回预报天气,哈哈哈自己慢慢玩。
    'extensions':'base',
    }
    return params

    结语

    想不到吧,这么快就结束了!!嘿嘿嘿嘿嘿,将代码移植到树莓派上,再写一个自动化脚本,就完事啦。

迁移Hexo操作

有时候我们可能要在另一台电脑上使用我们的博客平台,这时,需要我们重新再操作一个远程仓库,然后在创建文章吗???
很明显,这是不现实的,我们有什么办法解决这个问题呢?,有的,我们可以做一个远程仓库备份就可以了,这样我们下次使用只要配置好环境,直接clone下来就可以使用了,来,先看步骤!

  1. 在GitHub上创建远程分支(都是点点点的操作)

  2. 配置环境

    • Git
    • Node.js
    • Hexo
      • sudo npm install hexo-cli -g
  3. clone仓库(这里有好几步)

    • 克隆下来后,再创建一下分支git checkout -b dev,
    • 删除掉.git以外的文件,务必要这样做。注意:不是删除掉.git
    • 然后将Blog文件夹下的所有文件移到这个目录,并使用git操作一下,操作如下:
      1
      2
      3
      git add .
      git commit -m ''
      git push --set-upstream origin dev
    • 完成到这里就结束了这些部分的操作
    • 然后这样一下npm install (可能不需要)
  4. 开始正常写文章

    • 重复{Hexo配合GitHub搭建个人博客}里面的5~6步骤就可以了。
  5. 最后一步

    • 写完之后,得同步到dev分支一下奥
      1
      2
      3
      git add .
      git commit -m ''
      git push origin dev

Java/学习Java第二课

一、基本数据类型

  • 整数类型 byte,short,int,long
    • byte:-128~127
    • short:-32768~32767
    • int:-2147483648 ~ 2147483647
    • long: -9223372036854775808 ~ 9223372036854775807
  • 浮点数类型 float,double
    • float:3.4x10^38
    • double:1.79x10^308
  • 字符类型 char
    • 字符使用''表示
    • 字符串使用""表示,且需要String来表示
  • 布尔类型 boolean

二、三元运算符

  • b?x:y
    • 会首先计算b,如果b为true,则只计算x,否则,只计算y

三、数组类型

  • 例如定义一个整型数组
    • int[] a = new int[3];
    • 当然我们可以不用这样写,直接赋值,就不用写数组长度,上述代码非可以写成这样int[] a = new int[]{11,22,33};或者这样int[] a = {11,22,33};
  • 对于一个数组类型,我们可以使用length来获取数组的长度
    • a.length; //结果为3

四、程序的输入与输出

  • 输出(相对输入容易一点)
    • System.out.println("xxx");这就是输出语句,当然在输出中我们还可以大做文章
      • 这个时候语句可以写成System.out.printf("xxx");注意看print变了,后面怎么玩,其实和C语言是差不多相通的
  • 输入
    • 导入包import java.util.Scanner;
    • 新建一个对象Scanner scanner = new Scanner(System.in);
    • 读取输入int a = scanner.nextInt();
    • 上述三步才完成了基本的输入,第三部中有很多可以自己定义的地方,比如数据类型

五、流程控制

  • if else

    • 这个结构其实和Python极为相似,但是不同的是,这里的if后面的语句必须有括号括起来,否则会报错,并且Java的else if连用是分开的,在python中可以用elif来表示
      • eg 单个if使用
        1
        2
        3
        4
        int a = 8;
        if (a >= 5) {
        System.out.println("a>5");
        }
      • eg if和else连用
        1
        2
        3
        4
        5
        6
        int a = 8;
        if (a >= 15) {
        System.out.println("a>=15");
        }else{
        System.out.println("a<15");
        }
      • eg if和else if连用
        1
        2
        3
        4
        5
        6
        7
        8
        int a = 8;
        if (a >= 15) {
        System.out.println("a>=15");
        }else if (a >= 10){
        System.out.println("10<=a<15");
        }else{
        System.out.println("a<10");
        }
  • switch

    • switch其实就是一个多重选择,在给定选项中选择对应数据插入程序,程序执行相应操作
    • 一般语法结构
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      switch (option):
      case option1:
      xxx;
      break;
      case option2:
      xxx;
      break;
      ...
      default:
      xxx;
      break;
    • 注意上述表示,case会枚举option中的每一种操作,当然default表示,若枚举的都没有,直接执行对应结果就好,关于break我们在后面讲解
      • eg
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        import java.util.Scanner;

        public class LearnSwitch {
        public static void main(String[] args) {
        Scanner num = new Scanner(System.in);
        int n = num.nextInt();
        num.close();
        switch (n) {
        case 1:
        System.out.println("1");
        break;
        case 2:
        System.out.println("2");
        break;
        default:
        System.out.println("no in switch!");
        break;
        }
        }
        }
        该代码,若是输入1或者2就会被case捕捉到,执行相应语句,若没有捕捉到,则执行default语句。
  • while

    • while循环语句
    • 一般语法结构
      1
      2
      3
      while (条件){
      需要执行的语句
      }
    • 比如我们执行1+2+3+…+100
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      public class Sum{
      public static void main(String[] args){
      int n = 1;
      int sum = 0;
      while (n<=100){
      sum += n;
      n++;
      }
      System.out.println(sum);
      }
      }
  • do while

    • 和while相似,while是先判断再做,do while是先做再判断
    • 一般语法结构
      1
      2
      3
      do {
      需要执行的语句
      }while (条件);
  • for

    • emmmm,这个就写个代码吧,和c语言基本一致
      1
      2
      3
      4
      5
      6
      7
      8
      9
      public class Sum {
      public static void main(String[] args) {
      int sum = 0;
      for (int i=1; i<=100; i++) {
      sum = sum + i;
      }
      System.out.println(sum);
      }
      }
  • break && continue

    • 他们两兄弟在循环中用的最多,也是最频繁
    • break会跳出当前循环
    • continue则是提前结束本次循环

Java/学习Java第三课

一、面向对象

嗯?还没有对象?来帮你new一个,嘿嘿嘿嘿,开玩笑呢!
面向对象的简单理解,就是给你一个菜谱,你对着菜谱做菜,你今天做,明天做,后天做,只要是按着这个菜谱来做的,就是按照他的规则来,菜谱就是模板,而做出来的菜就是实例,实例是按照模板出来的,不管如何,他总是和模板相似,这其实就是面向对象的一个过程。而面向对象的三大基本特点:封装、继承、多态,我们来一一理解。

  • 封装
    • 简单来讲,封装就是一个模板,菜谱就是,它是高级大厨师封装出来的模板,给不会烧菜的小白做参考
  • 继承
    • 这点,可以看作是你用菜谱做菜,不管如何,你要用到里面加调料的步骤,这就是继承
  • 多态
    • 这个最好理解,就是你按照i菜谱做菜,可能真的是小白,第一次勉强做出来了,第二次…第无数次,可能每一次都不一样,而菜谱确是没有变的,这就是多态。

二、一个小小的尝试

  • 创建一个菜谱类Recipe,同时具有一些属性,分别为菜名name和菜的内容content
    1
    2
    3
    4
    class Recipe{
    public String name;
    Public String content;
    }
  • 创建一个实例,炒菜(比如:xxx)
    1
    Recipe xxx = new Recipe();

三、关键内容

刚刚我们尝试了一下,创建一个菜谱类,并包含两个字段,可以简单理解为类的属性,这里我们介绍定义在类中的方法,其实可以简单理解为C语言中的函数(ps:说的不是很谨慎,大概可以这样理解)

  • 方法

    1
    2
    3
    4
    修饰符 方法返回类型 方法名(方法参数列表) {
    若干方法语句;
    return 方法返回值;
    }

    关于修饰符,之前有提到过的
    public 公共的 允许外部调用
    private 私有的 不允许外部调用
    protected 受保护的 不允许外部调用,允许子类调用

  • 方法的传参
    我们在定义方法时,通常需要考虑时候要给这个方法传递参数,这一点很重要,而且在设计完方法后,调用时要对应使用。

    1
    2
    3
    public void setNameAndAge(String name, int age){
    ...
    }

    在使用这个方法时,务必要注意参数的类型

    • 可变参数 (用类型...定义)
      关于这个可变参数,简单理解就是参数可以接受一个数组,从而实现可变参数,注意,务必将属性设置为数组,否则接收参数就会错误!
      1
      2
      3
      public void setName(String... name){
      ...
      }
  • 构造方法
    不知你是否有过疑惑,刚刚实例化是怎么操作的?为什么可以这样?

    1
    Recipe xxx = new Recipe();

    其本质原理是编译器会默认生成一个构造方法,其本质长这个样子

    1
    2
    3
    4
    5
    6
    7
    8
    class Recipe{
    public String name;
    Public String content;

    public Recipe(){

    }
    }

    那么,编译器会自动默认一个,我们可以自己写一个麻?答案是可以的,而且还可以写参数哦,这样就可以实现使用类实例化时就给对象赋一个初始值哦。(ps:若是改变了构造方法,编译器就不会自动创建一个,这样我们在使用中要注意若是我们改变构造方法,让其变为可以接受参数的构造方法,原本不传参数的构造方法就失效了哦,要使用也很简单,再写一遍不就好了,哈哈哈,看下面代码部分。)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Recipe{
    public String name;
    Public String content;

    public Recipe(){

    }
    public Recipe(String name){
    this.name = name;
    }
    }
  • 方法的重载
    通俗来说就是方法名相同,但各自所需传递的参数不同,从而实现不同的功能。

失声痛哭之常用Linux命令

事情的经过是这样的,为了写学校的下发的模板文件不会乱码,我在Linux下创建了一个Windows7的虚拟机,使用共享文档的方式在win系统下编辑我放在Ubuntu中的文件(ps:还好是这么做的,不然小命没了),可是我昨天再开机的时候,emmm,我的天,我的Ubuntu20.04进不去图形化界面了,emmm,那我虚拟机啥的都没法子用了啊,我的文件有一天的还没同步啊。哎,喂,这么可以这样…….
其实我在使用Ubuntu20.04的时候发现这个系统的图形化界面的操作是多么的不友好,虽然图形化界面相对18.04好看了太多,但是bug也太多了吧…..,软件开几个后就会出现死机的现象,按什么都没有反应,包括使用Ctrl+Alt+F3来使用命令行模式都不可以,只能重启电脑…我….还有这输入法,我用的难受,终于再使用大半个月后系统的图形化界面崩了,进不去了….(ps:还好终端的模式可以进去….)
下面就来讲解我怎么把数据备份出来的,以便大家参考

  1. 确认需要备份的文件及大小(这里有一个坑,后面会有提)
    • 在/home目录下,使用df -sh [用户名]就可以查看这个用户目录下占用多大空间,我是52G…..我U盘才8G,这…
    • 可能是我没有安装对应的支持,导致我在终端模式下,/home/bean/下的文件夹,中文都是乱码…..,我真的是无语,都不知道这么移动了,毕竟我U盘容量小了,不然就可以直接sudo cp -rf * /U盘目录,哎…
  2. 准备一个大U盘,用来备份(越大越好)
  3. 挂载U盘,移动文件(还没结束哦!)
    • 使用fdisk -l查看U盘的盘符,使用sudo mount /dev/u盘盘符 /mnt就可以使用挂载命令将U盘挂载到/mnt目录下,直接使用sudo cp -rf * /mnt就可以了哦,小容量的自己想办法删些文件,没有乱码的可以在终端中删除,比如在Ubuntu的安装盘中使用试用安装模式来删除一些文件(我就是这样做的…)
    • 卸载U盘sudo umount /mnt你以为这样就好了么,呵呵呵,后面还有呢

当我安装好18.04后(图形化界面确实比20.04强多了),我打开一看….都是x,没权限打开….,使用ls -al或者ll一看,用户为root,用户组为root….我们这个使用就要更改用户和用户组,命令分别是chownchgrp,不过可以使用chown一个命令解决倒是,这里我将用户改为bean用户组改为bean,使用命令为sudo chown -R bean:bean *,这里的R表示同时改动当前文件夹下的子文件夹和文件,不然就得一个文件夹一个一个的改…..
我真的怕了,哎,哦对了,这篇文章就是使用我讲解hexo博客备份的方式来重新配置环境后再发出来的哦。